• Content Count

  • Joined

  • Last visited

  • Days Won


grelf last won the day on February 16 2019

grelf had the most liked content!

About grelf

  • Rank

Contact Methods

  • Website URL

Profile Information

  • Location
    NE England

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. I have explained my technique in some detail at
  2. It might help us to reply if we knew why you are drawing it "pixel by pixel". Why not canvas.context.drawimage ()? Enlarging an image by a factor of 3 is unlikely to produce a sharp result though. Better to start with the larger version and then reduce if or when necessary.
  3. Arjun, I have previously given in these pages links to my JavaScript course, which is completely free at I would be pleased to get some feedback about it. Some people seem to find it useful.
  4. I have written some advice about this on the last page of my JavaScript course, here: See the 4th item on the page.
  5. If you search for how to detect mobile devices by JavaScript you will find confusing information such as looking for the string "Mobi" in the browser identifier, and other unreliable stuff. In the past people checked screen size but that no longer works because some mobile devices have huge numbers of pixels. Even the usually reliable Mozilla Developer Network pages are contradictory on trying to detect touch screens. They have an article from 2011 which says to check whether the global window object has a property called ontouchstart (except that for Internet Explorer look at navigator.msMaxTouchPoints) but a recently updated (2019) page about TouchEvent (link below) says ontouchstart is still only an experimental proposal, not in the official specification of TouchEvent. So we cannot rely on browsers using it. I came to realise that in searching for "how to detect mobile" I was really asking the wrong question (as are many others). What really matters for my programs is whether the user has a keyboard (and if not, perhaps check for mouse or touch screen). As HTML5/JavaScript programmers (what this site is about) we do not have access to the internal system of the device we are running on, to check its hardware, so how can we do this? Here is my scheme. If a keyboard event occurs we know there is a keyboard. Similarly a mouse or touch event will confirm that the user has other capabilities. So in the constructor of the main program object do the following. this.keyable = false; // Until proven otherwise this.mouseable = false; this.touchable = false; var canvas = document.getElementById ("canvasId"); // Or whatever the id is canvas.addEventListener ("keydown", handleKeydown, false); canvas.addEventListener ("mousedown", handleMousedown, false); canvas.addEventListener ("touchstart", handleTouchstart, false); Then if any of those handlers is ever invoked you can set the corresponding boolean to true. For example (if we assume the global program object is called main): function handleKeydown (ev) { if (!main.keyable) { main.keyable = true; // There is a keyboard main.adjustScreenLayout (); // As necessary } // ... Go on to handle the key supplied in ev } Note that we do not want to adjust the layout every time an event comes in, only when the boolean first changes state. There is a potential problem though. If the user of a mobile device manages to invoke the onscreen keyboard it will generate keyboard events, fooling us. Our HTML5 game will not normally provide any way for the user to do this because we do not have access to the system level. However, if our HTML includes text input fields they would spoil things, so there must not be any such fields in the page. I think there is no way to find out whether key events come from a real or virtual keyboard. I have verified that my Surface Book only fires touch events from the screen, not from the touch pad. The latter fires mouse events. So detecting touch events does seem to indicate a touch screen and maybe that is all I need. If I detect a touch event I will assume that touch is what the user wants to use, regardless of whether there is a physical keyboard, and I should present the appropriate user interface layout. See also (and linked pages) That page shows that InternetExplorer and Safari (desktop) have no support for TouchEvent. That does not break my proposal above. It says that Safari on mobile does fully support TouchEvent.
  6. grelf

    confused on objects

    Yes, JavaScript handles objects in a very different way from most languages. It does not have explicit classes, instead you create "prototypes". However, it is a truly object oriented language and using objects in your programs is a good way to build a maintainable and extensible structure. I emphasise this in my free JavaScript course - start here: I introduce objects right at the beginning of the course but the full syntax is explained in Part 2. First you need to get the syntax for functions clear, because your example code is not right. I am keen to encourage others to explore the creative possibilities of pure HTML5/JavaScript before going on to consider frameworks and other libraries. Here is my biggest demonstrator of what can be done in the basic 2D graphics context: From there you can find a page about how the infinite terrain, contour maps and photographic scenes are programmed in plain JS.
  7. You can see an example of this kind of thing here: Not only does the map move as the user moves around on the ground (in the scene display) but you can separately scroll/pan the map by varying increments. If you check the "Orient map" box it rotates to any angle too. It is all done in the basic 2D canvas context. How it is done is described here: and you can easily find my JavaScript source files for details.
  8. You can indeed use a stroke path for clipping in the ordinary 2D context. See And I say more about it on my Forest design page: see
  9. Glad you liked it. The "attention to detail" is because I am using some of my own photos for the graphics, just edited a bit to provide transparency for windows and alternative layers for animating such things as the opening of doors. I have no requirement for going faster. My aim is to provide programs which will run on ANY device with an HTML5-capable browser, with a small loading time and without the user having to download anything else. I am also keen to encourage beginners to explore the creative possibilities of plain Javascript. I think I can see too many examples here of people trying to run before they can walk.
  10. 3D perspective is perfectly possible in the plain 2D canvas of HTML5/JavaScript without the overhead of any frameworks or libraries. As an example I have recently created a small game in response to a GameDev challenge relating to DOOM. I was troubled by a bug in my display when the player moved close to walls. I sat down and made some diagrams to help me get my thinking straight and then I was able to solve the bug. I thought others might find my diagrams useful so I am adding them here. My aim is to demonstrate that 3D perspective is perfectly possible in the plain 2D graphics context. I believe that it is simplest for beginners to start in this way, getting familiar with JavaScript without the additional learning curves presented by the various frameworks. You can read about what I have just done in relation to DOOM here (which has a link to my little game): The code was adapted from my earlier and more complex game, The Forest: (I now need to add a correction to the drawing of the mines in that program, having solved the bug).
  11. I assume we are taking about the standard '2d' graphics context for the canvas. There two simple approaches. 1. Create your scene as an image larger than the canvas. When you use context.drawImage (x, y) the x and y values (the coordinates for placing the top left corner of the image) can be negative. The context has a clipping region which by default is the whole area of the canvas. When you try to draw something which lies partly outside the canvas only the part within the cipping region will really be drawn, and seen. drawImage has some optional parameters, so context.drawImage (x, y, w, h) also scales the image as it draws so that the full width of the image is scaled up or down to w and the height to h. So panning can be achieved by varying x and zooming can be achieved with w and h. I have found the process to be extremely efficient - far better than could be achieved by processing the image pixel by pixel. 2. When you construct a scene place objects relative to an origin and with a scale factor, both of which you can vary. Use context.drawImage (x, y, w, h) again for each object. You can then vary the origin and scale factor as required. You can see an example of mine which mainly uses the second technique at - switch from the initial map to the scene and you will see lots of photographic images are drawn in each scene (saved as PNG files with transparency). If you turn you will see that objects move because the observer's viewing position has changed. I set things so that an object 5 metres away from the observer is drawn full scale but at any other distance d the scale factor is f = 5 / d. Then those final parameters are w = image.width * f and h = image.height * f. There is more description of my techniques at - I want to encourage others to use the wonderful creative medium of HTML5/JavaScript. I hope this helps.
  12. I have recently discovered a couple of useful pages about improving the speed of canvas operations. I will give links to those pages at the bottom of this item but first let me describe a good speed-up I got as a result of reading them. In my program The Forest ( I am continually looking for ways to improve the speed of drawing scenes. I have made several improvements already but this new one is very useful indeed. I have a Scene object with method draw() which is invoked whenever the observer moves or turns. From its earliest incarnation this method has reported how long it takes, so I can monitor what is going on. Its first line is var t0 = new Date ().getTime (); // ms and its last line calculates a difference and displays it in a status line on the HTML page: var dt = new Date ().getTime () - t0; forest.infoDiv.innerHTML = me.toString () + ", Drawn in " + dt + "ms (" + this.nDrawIms + " images)"; I have augmented that so that the constructor of forest.scene includes this.drawingTimes = ''; and a new final line at the end of draw(): this.drawingTimes += dt + '<br>'; I can cause drawing of the same scene over and over again by clicking a button labelled 'Look level' (as opposed to up or down buttons which would draw a slightly different view of the scene). This means I can build up a long string of forest.scene.drawingTimes. Then in a testing version I can press an otherwise unused key to dump those times as the innerHTML of a div in my HTML test page. The <br>s mean that I get a vertical column of values which I can then select, copy and paste into a spreadsheet (I use OpenOffice). Then it is easy to get the mean and standard deviation of the column. I did that twice for a large number of values. First with my last released version of The Forest and then with a tiny enhancement so that just before every time drawImage(im, x, y, width, height) is called I do this: x |= 0; y |= 0; Those are bitwise OR operations and their effect is simply to chop off the fractional parts of the screen coordinates x and y. This means that drawing starts on an exact pixel and does not require interpolation. The results: without the truncation (ORing) the mean time was 140.9ms with a standard deviation of 35.3ms; truncated the mean was 85.7ms and standard deviation 23.7ms. That is a very significant and useful improvement, so it will be going into my next version. The scene drawn here involved 1,693 calls to drawImage(), scaling each image (tree, ground, and other features) differently each time. From this big improvement I deduce that once drawImage() starts on an integer pixel then it uses integer pixels in the destination to decide where to get pixels from in the original image for scaling. In hindsight this is rather obvious really but I thought it would be useful to others to see how I went about proving the effect. I have noted before in this forum that the drawing time varies quite widely (as shown by the standard deviations) and I still attribute that to the workings of the garbage collector in the background. I should also point out that so far I have only measured this in FireFox. If you want to see more clearly what I am taking about, The Forest is at - from the initial map use the button (or key) to go to the scene. The pages which prompted this are:
  13. Matt, It's a shame no-one has yet replied to this because it is not a totally uninteresting question. (For beginners: There is clearly a distinction between 'entities' which are objects in a game and 'objects' which are particular kinds of things in JavaScript (and other languages). A game entity is very likely to be represented by a JavaScript object but we need to be clear about the difference.) The question is whether each entity should have a record of its coordinates (generally x, y, z in 3D space rather than a tile number) or instead each space position (or tile on a 2D ground) should have a list of entities which are currently at that position. As you suggest, there is a difference between fixed entities and mobile ones. Fixed ones can clearly be referenced directly from tiles so that they can be drawn whenever the relevant tile is drawn. Difficulties arise when the mobile entities move. Should we scan through all positions (tiles) to find entities to move or, given a moveable entity how do we find the tile at its position? It seems to me that the most natural way is for each entity to keep a record of its position. But then the question is, for any given space/ground position is there an entity here? The way I do it in The Forest ( is indeed for a moveable entity (represented by an object of type Mover) to have properties x and y for its position. Then when generating the terrain within method Terrain.terra (x, y) there is a test to see whether this.placed [x + ',' + y] is undefined. If not, that object property (which looks like an array element but is not) contains a reference to an entity at that position. This relies on the optional way of representing object properties in JavaScript, where the name of the property looks like an array index of type String. Notice how I build the index string in the most compact but unambiguous way possible (x + y would be ambiguous: many possible value of x and y could give the same sum). The lookup is really done as a hash table, so it is very efficient. When one of my entities moves from (x1, y1) to (x2, y2) the previous property of the object this.placed is deleted and a new one is created and given a reference to the entity: delete this.placed [x1 + ',' + y1]; this.placed [x2 + ',' + y2] = entity; I find this works very efficiently within my (effectively infinite) terrain. I have a few objects that move every time the user does something. (For beginners: see and pages around there for more about ways of writing object properties and for the use of the keyword delete.)
  14. I have managed to rewrite my scene drawing (in www. so that it does not reallocate two huge arrays and fill them with freshly created objects every time. This rewriting reduces the scene drawing time by about 30%. There is also less variability in the time taken from one scene to another which tends to confirm that garbage collection and reallocation were taking a lot of the time. Reallocation would be variable because it depends so much on what contiguous chunks of memory are available. I have written the following to show some things that developers may need to consider in their own code. My terrain is generated by a function of (x, y) position (in fact a method of an object of type Terra). It is a complicated function so it does not want to be done repeatedly for each position; instead its results must be held in arrays for subsequent reference during scene building. Two big arrays hold the results of that around the (moving) observer's current position to enable the scene to be drawn. For each position the arrays refer to an object of type ScenePoint which contains the distance and bearing of the point from the observer and other things (such as terrain details and amount of fogging for distant points). Each ScenePoint object has 10 properties so requires at least 80 bytes, probably more like 100 bytes allowing for the Object structure itself (I think that varies from browser to browser). One of the big arrays, around [x][y], goes out to the current view range which is user-selectable and can be up to 400 meters, so the array may have to be 801 x 801 to surround the observer. This is now allocated at the start of the program. Each array value will be a reference to a ScenePoint object so the array itself takes 8 x 801 x 801 = 5.1 megabytes. Then the 801 x 801 ScenePoint objects, also now allocated once at the start instead of freshly in each call to Scene.draw (), occupy about 100 x 801 x 801 = 64 megabytes. Another array, ahead , contains references to the same ScenePoint objects but is sorted during scene drawing so that the most distant points come first. This array does not contain references to objects behind the observer and so it is allocated as new Array (400 x 801). It requires a mere 8 x 400 x 801 = 2.6 megabytes. So my latest version of The Forest, v19.4.10 (see ) allocates just over 70 Mbytes when it starts and then no longer has to reallocate this (in many pieces) every time a scene is drawn. I still find it remarkable that my scene drawing is done in a couple of seconds even for the 400 metre horizon range. During that time the 'ahead' array is sorted too! When starting to draw a scene 'ahead' has to have all its elements set to undefined because as the observer moves and turns a varying number of points can lie ahead. I rely on the specification for Array.sort() which says that undefined elements get sorted to the end of an array. To support all this I have written a new JavaScript file to create one object of type Around. People may be interested to see it (below) but first Matt: Having made this change it was then easy to experiment with making 'around' a 1D array instead of 2D, calculating the index from x and y myself. I found no difference in performance (in FireFox). // Part of The Forest ( // Copyright (c) Graham Relf, UK, 2019 /** One object of this type is constructed at the start to avoid reallocating * big arrays every time a scene is drawn */ function Around () { var el = document.getElementById ("range"); this.aMid = 0; // The middle index of each x/y array // Find largest range user may select: for (var i = 0; i < el.options.length; i++) { var r = parseInt (el.options .value); if (r > this.aMid) this.aMid = r; } var wd = 2 * this.aMid + 1; this.aheadChange (this.aMid); this.around = new Array (wd); for (var x = 0; x < wd; x++) { this.around [x] = new Array (wd); for (var y = 0; y < wd; y++) { this.around [x][y] = new ScenePoint (0, 0, 0, 0, 0); } } } /** Use at the start of drawing a new scene * NB: mex, mey are rounded observer coordinates */ Around.prototype.init = function (mex, mey) { this.xOffset = this.aMid - mex; this.yOffset = this.aMid - mey; // Clear previous scene: for (var i = 0; i < this.nAhead; i++) this.ahead = undefined; this.nAhead = 0; }; /** Only used if user changes the range (and in Around constructor) */ Around.prototype.aheadChange = function (range) { this.ahead = new Array (2 * range * range); this.nAhead = 0; }; /** Add a ScenePoint object reference to the scene ahead */ Around.prototype.aheadPush = function (sp) { this.ahead [this.nAhead] = sp; this.nAhead++; }; /** How many active ScenePoint objects are currently ahead */ Around.prototype.aheadLength = function () { return this.nAhead; }; /** Get a reference to the ith ScenePoint object ahead */ Around.prototype.aheadGet = function (i) { return this.ahead ; }; /** Sort the ahead array in descending order of distance */ Around.prototype.aheadSort = function () { this.ahead.sort (ScenePoint.prototype.sort); }; /** Get a reference to the ScenePoint object at (x, y). * This is so that extra properties can be added to it. */ Around.prototype.aroundGet = function (x, y) { return this.around [x + this.xOffset][y + this.yOffset]; }; /** Set the fields of the ScenePoint at (x, y) as if freshly constructed */ Around.prototype.aroundSet = function (distance, bearing, x, y, odd) { var sp = this.around[x + this.xOffset][y + this.yOffset]; sp.fogNo = 0; = undefined; sp.building = undefined; sp.drawn = undefined; sp.clear = undefined; sp.d = distance; sp.b = bearing; sp.x = x; sp.y = y; sp.o = odd; }; Note that in my previous version of Scene.draw () each ScenePoint object was freshly constructed and subsequently might or might not get extra properties added (such as .tr or .drawn). That was poor practice really. For easier maintenance it should be clear in the constructor as to what properties an object can have.
  15. A method of generating dungeons can be seen here: except that I call them mines. A very small portion of the map generated by that can be seen below, in which the red squares are mineshafts coming down from the ground above (positions generated as part of a more complicated map, described elsewhere in the document linked above). You will note that the code shows that the map will be symmetrical about the line x = y but a slightly more complicated formula could change that. I use digits of PI shifted up to get more randomness. I only have one level of mines but obviously a third coordinate, z, could be included in the formula to get more levels. I first used this kind of method in the early 1980s and I have put copies of magazine articles about it on my history page: To see my code in action go to , go to the scene (key s) and move forward (up arrow).