Skip to content Skip to sidebar Skip to footer

Scrollable Board For Html5 Game Should Use Svg's Or Canvas

I wish to create a simple webgame that involves a tiled board. I have a collection of svg's for the background of each square (i.e one for grass, one for stone, one for dirt etc).

Solution 1:

enter image description here

The example below uses two modules svg to load images (Any image format will work) & board which handles panning, zooming & rendering. It also provides an onClick event which will give you an object that describes the tile that has been clicked on.

<!doctype html><html><head><metacharset="utf-8"><style>body {
				background-color: black;
			}
			
			canvas {
				display: block;
				margin: 30px auto 0px auto;
				border: solid 1px white;
				border-radius: 10px;
			}
		</style></head><body><canvasid="canvas"></canvas><scripttype="application/javascript">var svg = function() {
		
			"use strict";
			
			var svgImages = [];
			var areImagesLoaded = true;
			var isPageLoaded = false;
			
			addEventListener("load",function() { isPageLoaded = true; isFinished(); });
			
			varexports = {
				onload: function() {},
				request: null,
				get: null
			};
			
			functionisFinished() {
				if (isPageLoaded && areImagesLoaded) {
					exports.onload();
				}
			}
			
			functiononSvgError() {
				this.isDone = true;
				console.warn("SVG " + this.src + " failed to load.");
			}
			
			functiononSvgLoaded() {
				this.isDone = true;
				
				for (var id in svgImages) {
					if (!svgImages[id].isDone) {
						return;
					}
				}
				
				areImagesLoaded = true;
				isFinished();
			}
			
			functionrequest(id,path) {
				if (svgImages[id]) {
					return;
				}
				
				areImagesLoaded = false;
				
				var img = document.createElement("img");
				
				img.onerror = onSvgError;
				img.onload = onSvgLoaded;
				img.isDone = false;
				img.id = id;
				img.src = path;
				
				svgImages[id] = img;
			}
			
			functionget(id) {
				return svgImages[id];
			}
		
			exports.request = request;
			exports.get = get;
			
			returnexports;
		
		}();
		
		var board = function() {
		
			"use strict";
			
			var canvasWidth = 0;
			var canvasHeight = 0;
			var canvas = null;
			var ctx = null;
			var frameRequested = false;
			
			var tileWidth = 0;
			var tileHeight = 0;
			var tileTypes = [];
			
			var boardWidth = 0;
			var boardHeight = 0;
			var board = [];
			var hasInitialized = false;
			
			var camera = {
				x: 0.0,
				y: 0.0,
				zoom: 1.0
			};
			
			functionmapToBoard(x,y) {
				var invZoom = 1.0 / camera.zoom;
				
				return [
					(x - (canvasWidth >> 1)) * invZoom - camera.x,
					(y - (canvasHeight >> 1)) * invZoom - camera.y
				];
			}
			
			var isMouseDragging = false;
			var mouseStartX = 0;
			var mouseStartY = 0;
			var mouseLastX = 0;
			var mouseLastY = 0;
			
			var tileEvent = {
				background: "",
				foreground: "",
				x: 0,
				y: 0
			};
			
			functiononTileSelected(e) {
				
			}
			
			functiononMouseDown(e) {
				isMouseDragging = true;
			
				var bounds = canvas.getBoundingClientRect();
				
				mouseStartX = mouseLastX = e.clientX - bounds.left;
				mouseStartY = mouseLastY = e.clientY - bounds.top;
			}
			
			functiononMouseUp(e) {
				isMouseDragging = false;
				
				var bounds = canvas.getBoundingClientRect()
				var x = e.clientX - bounds.left - mouseStartX;
				var y = e.clientY - bounds.top - mouseStartY;
				var l = Math.sqrt(x * x + y * y);
				
				if (l < 2.0) {
					[x,y] = mapToBoard(e.clientX - bounds.left,e.clientY - bounds.top);
					
					if (x > 0 && y > 0 && x < boardWidth * tileWidth && y < boardHeight * tileHeight) {
						x = (x / tileWidth) | 0;
						y = (y / tileHeight) | 0;
						
						var tile = board[x + y * boardWidth];
						
						tileEvent.background = tile.background;
						tileEvent.foreground = tile.foreground;
						tileEvent.x = x;
						tileEvent.y = y;
					} else {
						tileEvent.background = "";
						tileEvent.foreground = "";
						tileEvent.x = -1;
						tileEvent.y = -1;
					}
				
					onTileSelected(tileEvent);
				}
			}
			
			functiononMouseMove(e) {
				if (hasInitialized && isMouseDragging) {
					var bounds = canvas.getBoundingClientRect();
					var x = e.clientX - bounds.left;
					var y = e.clientY - bounds.top;
					
					camera.x += (x - mouseLastX) / camera.zoom;
					camera.y += (y - mouseLastY) / camera.zoom;
					
					mouseLastX = x;
					mouseLastY = y;
					
					requestDraw();
				}
			}
			
			functiononWheel(e) {
				if (Math.sign(e.deltaY) === -1) {
					camera.zoom *= 1.1;
				} else {
					camera.zoom *= 0.9;
				}
				
				requestDraw();
			}
			
			functiondraw() {
				ctx.fillStyle = "gray";
				ctx.fillRect(-canvasWidth >> 1,-canvasHeight >> 1,canvasWidth,canvasHeight);
				
				var _tileWidth = tileWidth * camera.zoom;
				var _tileHeight = tileHeight * camera.zoom;
				var _ox = camera.x * camera.zoom;
				var _oy = camera.y * camera.zoom;
				var _x = _ox;
				var _y = _oy;
				
				for (var x = 0; x <boardWidth; ++x) {
					for (var y = 0; y < boardHeight; ++y) {
						var index = x + y * boardWidth;
						var tile = board[index];
						var background = tileTypes[tile.background];
						var foreground = tileTypes[tile.foreground];
						
						if (background) {
							ctx.drawImage(
								background,
								_x,
								_y,
								_tileWidth,
								_tileHeight
							);
						}
						
						if (foreground) {
							ctx.drawImage(
								foreground,
								_x,
								_y,
								_tileWidth,
								_tileHeight
							);
						}
						
						_y += _tileHeight;
					}
					
					_y = _oy;
					_x += _tileWidth;
				}
				
				frameRequested = false;
			}
			
			functionrequestDraw() {
				if (!frameRequested) {
					frameRequested = true;
					requestAnimationFrame(draw);
				}
			}
			
			return {
				BACKGROUND: 0,
				FOREGROUND: 1,
			
				setcanvas(canvasID) {
					if (!hasInitialized) {
						canvas = document.getElementById(canvasID);
						canvas.onmousedown = onMouseDown;
						canvas.onmouseup = onMouseUp;
						canvas.onmousemove = onMouseMove;
						canvas.onwheel = onWheel;
						ctx = canvas.getContext("2d");
					}
				},
				
				setcanvasWidth(w) {
					if (!hasInitialized && canvas) {
						canvasWidth = canvas.width = w;
					}
				},
				
				setcanvasHeight(h) {
					if (!hasInitialized && canvas) {
						canvasHeight = canvas.height = h;
					}
				},
				
				settileWidth(w) {
					if (!hasInitialized) {
						tileWidth = w;
					}
				},
				
				settileHeight(h) {
					if (!hasInitialized) {
						tileHeight = h;
					}
				},
				
				setwidth(w) {
					if (!hasInitialized) {
						boardWidth = w;
					}
				},
				
				setheight(h) {
					if (!hasInitialized) {
						boardHeight = h;
					}
				},
				
				setonTileSelected(callback) {
					onTileSelected = callback;
				},
				
				getwidth() {
					return boardWidth;
				},
				
				getheight() {
					return boardHeight;
				},
				
				getonTileSelected() {
					return onTileSelected;
				},
				
				defineTileTypes: function(types) {
					if (types.length % 2 !== 0) {
						return;
					}
				
					for (var i = 0; i < types.length; i += 2) {
						var id = types[i];
						var img = types[i + 1];
						
						tileTypes[id] = img;
					}
				},
				
				init: function() {
					camera.x = -(boardWidth >> 1) * tileWidth;
					camera.y = -(boardHeight >> 1) * tileHeight;
					ctx.translate(canvasWidth >> 1,canvasHeight >> 1);
				
					board.length = boardWidth * boardHeight;
					
					for (var i = 0; i < board.length; ++i) {
						board[i] = {
							background: "",
							foreground: ""
						};
					}
					
					hasInitialized = true;
					requestAnimationFrame(draw);
				},
				
				set: function(type,id,x,y) {
					if (hasInitialized
					&& tileTypes[id]
					&& x > -1 
					&& x < boardWidth
					&& y > -1
					&& y < boardHeight) {
						var index = x + y * boardWidth;
						
						if (type === this.BACKGROUND) {
							board[index].background = id;
						} else {
							board[index].foreground = id;
						}
						
						requestDraw();
					}
				}
			};
		
		}();
		
		voidfunction() {
		
			"use strict";
			
			svg.request("grass","https://i.stack.imgur.com/CkvU7.png");
			svg.request("water","https://i.stack.imgur.com/an6a5.png");
			
			svg.onload = function() {
				board.canvas = "canvas";
				board.canvasWidth = 180;
				board.canvasHeight = 160;
				
				board.tileWidth = 25;
				board.tileHeight = 25;
				
				board.width = 20;
				board.height = 20;
				
				board.defineTileTypes([
					"GRASS",svg.get("grass"),
					"WATER",svg.get("water")
				]);
				
				board.init();
				
				for (var x = 0; x < board.width; ++x) {
					for (var y = 0; y < board.height; ++y) {
						board.set(board.BACKGROUND,"WATER",x,y);
						
						if (Math.random() > 0.2) {
							board.set(board.BACKGROUND,"GRASS",x,y);
						} else {
							board.set(board.BACKGROUND,"WATER",x,y);
						}
					}
				}
			}
			
			board.onTileSelected = function(e) {
				if (e.background === "GRASS") {
           board.set(board.BACKGROUND,"WATER",e.x,e.y);
        } else {
           board.set(board.BACKGROUND,"GRASS",e.x,e.y);
        }
			}
			
		}();
		
		</script></body></html>

Post a Comment for "Scrollable Board For Html5 Game Should Use Svg's Or Canvas"