Open Source PBBG World Builder -released-

Got a project near completion? Got a project with lots of screens and media? This is the place. This is for nearly finished and Projects with lots of media.
Post Reply
User avatar
Jackolantern
Posts: 10891
Joined: Wed Jul 01, 2009 11:00 pm

Open Source PBBG World Builder -released-

Post by Jackolantern »

Background: A couple of days ago I realized I really, really needed a point'n'click graphical map editor for my current project. As I made it, I tried to make it fairly generic (allowing different terrain image sizes, different amount of cells, etc.) with the plan to release it. I just finished it this afternoon and figured I would put it up. I will try to get it up and running on a web server so people can try it out before dedicating the time to download it and run the SQL statement to set up the database. For now I have some screenshots linked below.

What it does: You first load the "worldbuilderconfig.html" page and enter in the pixel width of your square terrain textures. Then you specify the width and height in cells of your map (each cell is the size of one terrain image). Click "Submit" to be taken into the editor. Click a Terrain tile to automatically fill the map with the terrain texture. Then click a "prop icon" to select. Clicking on the map with a prop selected will place the prop in that area. Enter the name of the map, zone, and an X and Y location of the map in the game world. Zone, X and Y locations don't need to be present in your game. I simply needed them for travel in my game. If you don't need them, simply add a dummy value to them. Clicking the "Save Map" button will save the map details to the database.

Current Limitations: Currently, the background texture must be square, although you can use any size (within reason considering the size of the browser window and your cell size selections). Also, there is a limit of 26 props that can be added. It should be self explanatory to add more, but the design of my game that I made this editor for dictated that I needed to have a limit. If you want to increase the limit, add more variables to send on AJAX $.post() call, increase the limit in the IF structure in the '#field' event handler, and add the extra fields in the 'saveworld.php' file and in the database.

Technology Used: The project uses HTML, Javascript, jQuery, PHP and a tad of CSS when needed. The application is mostly unstyled, since this is a developer-facing application not suitable for public-facing use.

Current Version: This application is being released as v.0.3.2. It is still technically in beta, although currently it is fully functional.

To-Do: There is definitely some cleaning-up that could be done. For the life of me I could not get arrays passed the way I wanted through jQuery. They would be passed but would not be read correctly in PHP. So therefore I had to pass each variable individually, which added some extra bulk to the "Save" functionality in the client-side code that could really be cleaned up by handling all the values by array.

Also the application could really handle a "Load" function to load a saved map back into the editor for further editing. The application will be considered to be still in beta until it has this functionality.

I would also like to see it have a "ctrl+z" undo feature with a managed history of all the additions to the map to step back.

What is included: 1. worldbuilderconfig.html (used first when accessing the editor to set up the parameters) 2. worldbuilder.php (the actual client-side editor) 3. saveworld.php (the PHP backend file for saving to the database) 4. SQL code (to create the proper database structure) 5. maprecreator.html (the first file used to pull up the map; mostly just for testing) 6. mapshow.php (the second file used to pull up the map; mostly for testing and as an example of how to recreate the map from the database) 7. connect.php (a pretty run of the mill file, but I am including it so people using the "mysql" library can know how to setup their connect file with the "mysqli" library)

What is not included: jQuery, for space considerations. You can download the latest jQuery release here. You need to adjust the <script> tag that links the jQuery file to the scripts since it may be in a different directory and may be named differently (I trim the name of my jQuery down so it is easier to type while I am writing code).

Expected folder setup: PBBG World Builder is currently set up to expect that you have World Builder in a sub-folder inside your main game folder on your development machine. It is currently coded to go up one folder back into your main, and then go into a folder named "images" for your prop images to be loaded into the editor. In the "images folder" is another folder named "terrain" where you keep your terrain images to be loaded into the editor.

License: This application is being expressly released under the MIT license:
MIT License wrote:Copyright (c) 2010 Tim Crouch

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
The indelible lord of tl;dr
User avatar
Jackolantern
Posts: 10891
Joined: Wed Jul 01, 2009 11:00 pm

Re: Open Source PBBG World Builder -released-

Post by Jackolantern »

Source Code:

worldbuilderconfig.html:

Code: Select all

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>World Builder Config</title>
<meta name="" content="">
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
</head>
<body>
<!--
/* =====  PBBG World Builder v.0.3.2 =====
*  created Nov 18, 2010   copyright 2010 Tim Crouch
*  Released under the MIT license http://www.opensource.org/licenses/mit-license.php
*/
-->

<h2>Instructions:</h2> <br />

1. Choose how many pixels across the terrain texture is. Terrain textures must be perfect squares.<br />
2. Enter the dimensions of the map you wish to create. The world builder will use this and the texture size to determine the map size. <br />
3. Click submit to go to the world builder main page.<br />

<form action="worldbuilder.php" method="get">
Width in pixels of terrain textures: <br />
<input type="text" name="terrainwidth" size="6" /><br /><br />
Number of cells across: <br />
<input type="text" name="mapwidth" size="6" /><br /><br />
Number of cells down: <br />
<input type="text" name="mapheight" size="6" /><br /><br />
<input type="submit" value="Submit" />

</form>

</body>
</html>
The indelible lord of tl;dr
User avatar
Jackolantern
Posts: 10891
Joined: Wed Jul 01, 2009 11:00 pm

Re: Open Source PBBG World Builder -released-

Post by Jackolantern »

Note:*****Newer version (v.0.4.10) below*****

worldbuilder.php

Code: Select all

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>World Builder</title>
<meta name="" content="">
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
<script type="text/javascript" src="../js/jquery141.js"></script>
<?php 
	echo '<script type="text/javascript">
	var propSize = '.$_GET['terrainwidth'].';
	var mapWidth = '.$_GET['mapwidth'].';
	var mapHeight = '.$_GET['mapheight'].';
</script>';
?>
<script type="text/javascript">
	$(function() {
		/* =====  PBBG World Builder v.0.3.3 =====
		*  created Nov 18, 2010   copyright 2010 Tim Crouch
		*  Released under the MIT license http://www.opensource.org/licenses/mit-license.php
		*/
		
		
		//used to fill the field in the World Builder
		var terrainChoice = '';
		//the associative array to hold the image names (aka filenames) and their x and y locations (stored as a ordered pair)
		var propLocations = new Array();
		//used to hold the current prop choice as a path file. Used to display on the field and to send through AJAX
		var currentProp = '';
		//a variable to keep a count of how many props have been placed
		var propCount = 0;
		//2 variables to hold the size of the chosen element
		var theElementX = 24;
		var theElementY = 24;
		
		//hide the aiming div until needed
		$('#aiming').hide();
		
		//the event handler for clicking on a prop image
		$('.prop').click(function(evnt) {
			//display the current selection under the map in the "currently selected" icon
			var currentImgSrc = $(evnt.target).attr('src');
			$('#currentDiv').html('<img id="currentImg" src="' + currentImgSrc + '" />');
			
			//store the prop's file path for use to display on the field
			currentProp = currentImgSrc;
			
		});
		
		//track mouse movement in the field 
		$('#board').click(function(pos) {
			//Make sure a prop is selected before doing anything, and make sure no more than 25 props are added
			if ((currentProp != '') && (propCount <= 25)) {
				//get the x and y values of mouse click minus the offset of the field
				var xVal = pos.pageX - this.offsetLeft;
				var yVal = pos.pageY - this.offsetTop;
				$('#mouseLocation').html('X: ' + xVal + ' Y: ' + yVal);
				
				//%%%%%%%Begin process of adding the prop to the board%%%%%%%%%%%%%%%%%
				//increase propCount by one to show one more prop added to the field				
				$('#propCounter').html('Props: ' + propCount + '/25');
				
				//Adjust for pointer differences
				xVal = xVal + 9;
				yVal = yVal + 9;
				
				
				$('#board').append('<img id="prop' + propCount + '" class="setProp" style="position: absolute; left: ' + xVal + 'px; top: ' + yVal + 'px;" src="' + currentProp + '" />' );
				
				//%%%%%%%%ADD THE PROP FILENAME AND LOCATION TO THE propLocations ARRAY%%%%%%%%
				var myPropArray = currentProp.split('/');
				var propName = myPropArray[2];
				//CHANGED ';' to ':' temporarily
				propLocations['prop' + propCount] = xVal + ' ' + yVal + ' ' + propName;
				$('#propnumber').html(propLocations['prop' + propCount]);	
				
				propCount++;			
				
			}
			
		});
		
		//Add event handler for the mouse movement to add a placing cell for movement
		$('#board').mousemove(function(evnt) {
			$('#aiming').attr('style', 'position: absolute; width: ' + theElementX + '; height: ' + theElementY + '; left: ' + evnt.pageX + '; top: ' + evnt.pageY + ';');
			
		});
		
		//Show the aiming div when the mouse enters the board
		$('#board').mouseenter(function() {
			$('#board').append('<div id="aiming" style="position: absolute; width: ' + theElementX + '; height: ' + theElementY + '; left: 10; top: 10;"');
			theElementX = $('[src="' + currentProp + '"]').width();
			theElementY = $('[src="' + currentProp + '"]').height();	
		});
		
		//Hide the aiming reticle when the mouse exits the board
		$('#board').mouseleave(function() {
			$('#aiming').remove();
		});
		
		//event handler for clicking on a terrain texture
		$('.terrain').click(function(evnt) {
			//remove any texture that may already be there
			$('.backgroundTile').remove();
		
			//get the terrain image src
			var terrainSrc = $(evnt.target).attr('src');
			//alert('Selected a terrain texture. Src: ' + terrainSrc);
			
			//Figure out how many cells need to be filled
			var fillAmount = mapHeight * mapWidth; 
			
			
			//add the images for the background
			for (var count = 0; count < fillAmount; count++) {
				$('#board').append('<img id="backgroundTile' + count + '" class="backgroundTile" src="' + terrainSrc + '" />');
			}
			
			//split the terrain file path to get the file name alone
			var terrainArray = terrainSrc.split('/');
			
			//terrainChoice = myTerrainArray[3];
			terrainChoice = terrainArray[3];
			
		});
		
		//the event handler for the Save Map button
		$('#saveButton').click(function(evnt) {
			//extract values from the save fields
			var mapNameValue = $('#mapname').val();
			var zoneName = $('#zonename').val();
			var mapXCoord = $('#mapxcoord').val();
			var mapYCoord = $('#mapycoord').val();
			//$('#propnumber').html('Map name: ' + mapNameValue + '__ Map X: ' + mapXCoord + '__ Map Y: ' + mapYCoord);
			
			//Fill in any unused prop slots
			for (var fill = 0; fill < 26; fill++) {
				if (propLocations['prop' + fill] === undefined) {
				//if (!(propLocations['prop' + fill])) {
					propLocations['prop' + fill] = 'none';
				}
			}
			
			//Add the rest of the data to the array to be passed to the server
			propLocations['name'] = mapNameValue;
			propLocations['zone'] = zoneName;
			propLocations['mapx'] = mapXCoord;
			propLocations['mapy'] = mapYCoord;
			
			//send the data to the saveworld.php file through an AJAX post call				
			$.post('saveworld.php', {
					name: propLocations['name'],
					zone: propLocations['zone'],
					mapx: propLocations['mapx'],
					mapy: propLocations['mapy'],
					terrain: terrainChoice,
					terrainwidth: propSize,
					cellwidth: mapWidth,
					cellheight: mapHeight,
					prop0: propLocations['prop0'], prop1: propLocations['prop1'], prop2: propLocations['prop2'], prop3: propLocations['prop3'], prop4: propLocations['prop4'], prop5: propLocations['prop5'], prop6: propLocations['prop6'], prop7: propLocations['prop7'], prop8: propLocations['prop8'], prop9: propLocations['prop9'], prop10: propLocations['prop10'], prop11: propLocations['prop11'], prop12: propLocations['prop12'], prop13: propLocations['prop13'], prop14: propLocations['prop14'], prop15: propLocations['prop15'], prop16: propLocations['prop16'], prop17: propLocations['prop17'], prop18: propLocations['prop18'], prop19: propLocations['prop19'], prop20: propLocations['prop20'], prop21: propLocations['prop21'], prop22: propLocations['prop22'], prop23: propLocations['prop23'], prop24: propLocations['prop24'], prop25: propLocations['prop25']					 
				}, function(data) {
					if (data == 'success') {
						alert('Map saved to the database.');
					} else {
						alert('An error occured.');
					}					
				}
			);
			
			
			
		});
		
		$('#testButton').click(function() {		
			alert('X: ' + theElementX + ' Y: ' + theElementY);	
			//$('#testConsole').html('Terrain variable: ' + terrainChoice);
		});
	});
</script>
<?php
	//pull the previous form values from the URL and get them ready to size the div in the CSS
	$terrainTexture = $_GET['terrainwidth'];
	$mapHeight = $_GET['mapheight'];
	$mapWidth = $_GET['mapwidth'];
	
	//the actual div dimensions are the products of the terrain pixels by the number of cells desired
	$mapHeightPixels = $terrainTexture * $mapHeight;
	$mapWidthPixels = $terrainTexture * $mapWidth;
?>
<style rel="stylesheet" type="text/css">
	#board {
		position: relative;
		width: <?php echo $mapWidthPixels; ?>px;
		height: <?php echo $mapHeightPixels; ?>px;
		background-color: #5054F4;
		/*float: left;*/
	}
	#imagesSelector, #terrainsSelector {
		padding: 10px;
		margin: 10px;
		border: 2px solid #000000;
	}
	.backgroundTile {
		z-index: 1;
	}
	.setProp {
		z-index: 10;
	}
	#aiming{
		border: 1px solid #000000;
	}
		
	
</style>


</head>
<body>
<div id="main">
<div id="board">
</div>

<div class="clear" id="diagnostics">
	Currently selected:<br />
	<div id="currentDiv"></div><br />
	<!--TESTING***********************************-->
	<div id="mouseLocation"></div><br />
	<!--TESTING***********************************-->
	<div id="propnumber"></div>
	<div id="propCounter">Props: 0</div>
	<!--TESTING***********************************-->
	<div id="testConsole"></div>
</div>
</div>

<div id="imagesSelector">
Prop Icons <br />
<?php
	//pull up all the images up folder up, then into the images folder
	$files = glob("../images/*.*");
	for ($i = 1; $i < count($files); $i++) {
		$imgsrc = $files[$i];
		echo '<img id="'.$imgsrc.'" class="prop" src="'.$imgsrc.'" alt="random image" />';
	}
?>
</div>


<div id="terrainsSelector">
Terrain Choice <br />
<?php
	//pull up all the terrain images one folder up, then into the images folder, then into the terrain folder
	$files = glob("../images/terrain/*.*");
	for ($i = 1; $i < count($files); $i++) {
		$imgsrc = $files[$i];
		echo '<img id="'.$imgsrc.'" class="terrain" src="'.$imgsrc.'" alt="random image" />';
	}
?>
</div><br />
Name of map: <br />
<input type="text" id="mapname" size="25" /><br /><br />
Name of zone: <br />
<input type="text" id="zonename" size="25" /><br /><br />
X coordinate of map:<br />
<input type="text" id="mapxcoord" size="5" /><br />
Y coordinate of map:<br />
<input type="text" id="mapycoord" size="5" /><br />
<input type="submit" id="saveButton" value="Save Map" />
<!--TESTING***********************************************************-->
<input type="submit" id="testButton" value="Test Button" />




</body>
</html>
The indelible lord of tl;dr
User avatar
Jackolantern
Posts: 10891
Joined: Wed Jul 01, 2009 11:00 pm

Re: Open Source PBBG World Builder -released-

Post by Jackolantern »

saveworld.php

Code: Select all

<?php

	/* =====  PBBG World Builder v.0.3.2 =====
	*  created Nov 18, 2010   copyright 2010 Tim Crouch
	*  Released under the MIT license http://www.opensource.org/licenses/mit-license.php
	*/
	
	$props = array();
	
	include_once "connect.php";
	
	$name = $_POST['name']; $zone = $_POST['zone']; $mapx = $_POST['mapx']; $mapy = $_POST['mapy']; $terrain = $_POST['terrain']; $terrainwidth = $_POST['terrainwidth']; $cellwidth = $_POST['cellwidth']; $cellheight = $_POST['cellheight']; $props[0] = $_POST['prop0']; $props[1] = $_POST['prop1']; $props[2] = $_POST['prop2']; $props[3] = $_POST['prop3']; $props[4] = $_POST['prop4']; $props[5] = $_POST['prop5']; $props[6] = $_POST['prop6']; $props[7] = $_POST['prop7']; $props[8] = $_POST['prop8']; $props[9] = $_POST['prop9']; $props[10] = $_POST['prop10']; $props[11] = $_POST['prop11']; $props[12] = $_POST['prop12']; $props[13] = $_POST['prop13']; $props[14] = $_POST['prop14']; $props[15] = $_POST['prop15']; $props[16] = $_POST['prop16']; $props[17] = $_POST['prop17']; $props[18] = $_POST['prop18']; $props[19] = $_POST['prop19']; $props[20] = $_POST['prop20']; $props[21] = $_POST['prop21']; $props[22] = $_POST['prop22']; $props[23] = $_POST['prop23']; $props[24] = $_POST['prop24']; $props[25] = $_POST['prop25'];	
	
	
	//%%%%%%%%%%%%%%%%%%%Start process for adding to the database%%%%%%%%%%%%%%%%%%%%%%%5
	
	
	$yvalues = array();
	$xvalues = array();
	$namevalues = array();
	//CHANGED FOR TESTING. CONDITION should be $z < count($props)
	for ($z = 0; $z < count($props); $z++) {
		//Make the offset for the prop string
		$placeHolder = 'prop' + $z;
		//get the prop string
		
		if ($props[$placeHolder] != "none") {
			$queryString = $props[$placeHolder];
			//create an array holding 0. the x and y values and 1. the filename
			$nameAndCoordArray = explode(' ', $queryString);
			//explode the x and y values
		
			//store exploded values
			$xvalues[$z] = $nameAndCoordArray[0];
			$yvalues[$z] = $nameAndCoordArray[1];
			$namevalues[$z] = $nameAndCoordArray[2];
		} else {
			$xvalues[$z] = -1;
			$yvalues[$z] = -1;
			$namevalues[$z] = "none";
		}
			
		
	}
	
	//concat map coordinate into string	
	$coordinateIn = $mapx.",".$mapy;
	
	//Enter all of the map data into the db.	
	mysqli_query($db, "INSERT into worldmaps(name, zone, coordinates, terrain, terrainwidth, cellwidth, cellheight, prop0, X0, Y0, prop1, X1, Y1, prop2, X2, Y2, prop3, X3, Y3, prop4, X4, Y4, prop5, X5, Y5, prop6, X6, Y6, prop7, X7, Y7, prop8, X8, Y8, prop9, X9, Y9, prop10, X10, Y10, prop11, X11, Y11, prop12, X12, Y12, prop13, X13, Y13, prop14, X14, Y14, prop15, X15, Y15, prop16, X16, Y16, prop17, X17, Y17, prop18, X18, Y18, prop19, X19, Y19, prop20, X20, Y20, prop21, X21, Y21, prop22, X22, Y22, prop23, X23, Y23, prop24, X24, Y24, prop25, X25, Y25) VALUES ('$name', '$zone', '$coordinateIn', '$terrain', '$terrainwidth', '$cellwidth', '$cellheight', '$namevalues[0]', '$xvalues[0]', '$yvalues[0]', '$namevalues[1]', '$xvalues[1]', '$yvalues[1]', '$namevalues[2]', '$xvalues[2]', '$yvalues[2]', '$namevalues[3]', '$xvalues[3]', '$yvalues[3]', '$namevalues[4]', '$xvalues[4]', '$yvalues[4]', '$namevalues[5]', '$xvalues[5]', '$yvalues[5]', '$namevalues[6]', '$xvalues[6]', '$yvalues[6]', '$namevalues[7]', '$xvalues[7]', '$yvalues[7]', '$namevalues[8]', '$xvalues[8]', '$yvalues[8]', '$namevalues[9]', '$xvalues[9]', '$yvalues[9]', '$namevalues[10]', '$xvalues[10]', '$yvalues[10]', '$namevalues[11]', '$xvalues[11]', '$yvalues[11]', '$namevalues[12]', '$xvalues[12]', '$yvalues[12]', '$namevalues[13]', '$xvalues[13]', '$yvalues[13]','$namevalues[14]', '$xvalues[14]', '$yvalues[14]', '$namevalues[15]', '$xvalues[15]', '$yvalues[15]', '$namevalues[16]', '$xvalues[16]', '$yvalues[16]', '$namevalues[17]', '$xvalues[17]', '$yvalues[17]', '$namevalues[18]', '$xvalues[18]', '$yvalues[18]', '$namevalues[19]', '$xvalues[19]', '$yvalues[19]', '$namevalues[20]', '$xvalues[20]', '$yvalues[20]', '$namevalues[21]', '$xvalues[21]', '$yvalues[21]', '$namevalues[22]', '$xvalues[22]', '$yvalues[22]', '$namevalues[23]', '$xvalues[23]', '$yvalues[23]', '$namevalues[24]', '$xvalues[24]', '$yvalues[24]', '$namevalues[25]', '$xvalues[25]', '$yvalues[25]')") or die ("Call failed");
	
	//tell the client if the save was a success
	echo "success";
	
	
?>
SQL Code (replace "<<<your db<<<" with the name of your database):

Code: Select all

-- phpMyAdmin SQL Dump
-- version 3.2.0.1
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: Nov 20, 2010 at 12:04 AM
-- Server version: 5.1.36
-- PHP Version: 5.3.0

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";

--
-- Database: `<<<your db<<<`
--

-- --------------------------------------------------------

--
-- Table structure for table `worldmaps`
--

CREATE TABLE IF NOT EXISTS `worldmaps` (
  `mapid` int(4) NOT NULL AUTO_INCREMENT,
  `name` varchar(25) NOT NULL,
  `zone` varchar(25) NOT NULL,
  `coordinates` varchar(8) NOT NULL,
  `terrain` varchar(45) NOT NULL,
  `terrainwidth` int(3) NOT NULL,
  `cellwidth` int(3) NOT NULL,
  `cellheight` int(3) NOT NULL,
  `prop0` varchar(30) NOT NULL,
  `X0` int(4) NOT NULL,
  `Y0` int(4) NOT NULL,
  `prop1` varchar(30) NOT NULL,
  `X1` int(4) NOT NULL,
  `Y1` int(4) NOT NULL,
  `prop2` varchar(30) NOT NULL,
  `X2` int(4) NOT NULL,
  `Y2` int(4) NOT NULL,
  `prop3` varchar(30) NOT NULL,
  `X3` int(4) NOT NULL,
  `Y3` int(4) NOT NULL,
  `prop4` varchar(30) NOT NULL,
  `X4` int(4) NOT NULL,
  `Y4` int(4) NOT NULL,
  `prop5` varchar(30) NOT NULL,
  `X5` int(4) NOT NULL,
  `Y5` int(4) NOT NULL,
  `prop6` varchar(30) NOT NULL,
  `X6` int(4) NOT NULL,
  `Y6` int(4) NOT NULL,
  `prop7` varchar(30) NOT NULL,
  `X7` int(4) NOT NULL,
  `Y7` int(4) NOT NULL,
  `prop8` varchar(30) NOT NULL,
  `X8` int(4) NOT NULL,
  `Y8` int(4) NOT NULL,
  `prop9` varchar(30) NOT NULL,
  `X9` int(4) NOT NULL,
  `Y9` int(4) NOT NULL,
  `prop10` varchar(30) NOT NULL,
  `X10` int(4) NOT NULL,
  `Y10` int(4) NOT NULL,
  `prop11` varchar(30) NOT NULL,
  `X11` int(4) NOT NULL,
  `Y11` int(4) NOT NULL,
  `prop12` varchar(30) NOT NULL,
  `X12` int(4) NOT NULL,
  `Y12` int(4) NOT NULL,
  `prop13` varchar(30) NOT NULL,
  `X13` int(4) NOT NULL,
  `Y13` int(4) NOT NULL,
  `prop14` varchar(30) NOT NULL,
  `X14` int(4) NOT NULL,
  `Y14` int(4) NOT NULL,
  `prop15` varchar(30) NOT NULL,
  `X15` int(4) NOT NULL,
  `Y15` int(4) NOT NULL,
  `prop16` varchar(30) NOT NULL,
  `X16` int(4) NOT NULL,
  `Y16` int(4) NOT NULL,
  `prop17` varchar(30) NOT NULL,
  `X17` int(4) NOT NULL,
  `Y17` int(4) NOT NULL,
  `prop18` varchar(30) NOT NULL,
  `X18` int(4) NOT NULL,
  `Y18` int(4) NOT NULL,
  `prop19` varchar(30) NOT NULL,
  `X19` int(4) NOT NULL,
  `Y19` int(4) NOT NULL,
  `prop20` varchar(30) NOT NULL,
  `X20` int(4) NOT NULL,
  `Y20` int(4) NOT NULL,
  `prop21` varchar(30) NOT NULL,
  `X21` int(4) NOT NULL,
  `Y21` int(4) NOT NULL,
  `prop22` varchar(30) NOT NULL,
  `X22` int(4) NOT NULL,
  `Y22` int(4) NOT NULL,
  `prop23` varchar(30) NOT NULL,
  `X23` int(4) NOT NULL,
  `Y23` int(4) NOT NULL,
  `prop24` varchar(30) NOT NULL,
  `X24` int(4) NOT NULL,
  `Y24` int(4) NOT NULL,
  `prop25` varchar(30) NOT NULL,
  `X25` int(4) NOT NULL,
  `Y25` int(4) NOT NULL,
  PRIMARY KEY (`mapid`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=27 ;

--
-- Dumping data for table `worldmaps`
--

The indelible lord of tl;dr
User avatar
Jackolantern
Posts: 10891
Joined: Wed Jul 01, 2009 11:00 pm

Re: Open Source PBBG World Builder -released-

Post by Jackolantern »

mapcreator.html

Code: Select all

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Map Recreator</title>
<meta name="" content="">
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
</head>
<body>
<!--
/* =====  PBBG World Builder v.0.3.2 =====
*  created Nov 18, 2010   copyright 2010 Tim Crouch
*  Released under the MIT license http://www.opensource.org/licenses/mit-license.php
*/
-->
<form action="mapshow.php" method="post">
	Which map to recreate? (map ID)<br />
	<input type="text" name="mapid" size="4" /><br />
	<input type="submit" value="Get map" />
</form>

</body>
</html>
mapshow.php:

Code: Select all

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Map Recreator</title>
<meta name="" content="">
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
<script type="text/javascript" src="../js/jquery141.js"></script>
<?php
	/* =====  PBBG World Builder v.0.3.2 =====
	*  created Nov 18, 2010   copyright 2010 Tim Crouch
	*  Released under the MIT license http://www.opensource.org/licenses/mit-license.php
	*/

	include "connect.php";
	
	$pullMap = $_POST['mapid'];
	
	$mapData = mysqli_fetch_assoc(mysqli_query($db, "SELECT * FROM worldmaps WHERE mapid='$pullMap'"));
	
	if (!$mapData) {
		echo "Could not pull up map data.";
		exit();
	}
	
	$totalMapWidth = $mapData['terrainwidth'] * $mapData['cellwidth'];
	$totalMapHeight = $mapData['terrainwidth'] * $mapData['cellheight'];
	$totalCells = $mapData['cellheight'] * $mapData['cellwidth'];
	$bgTerrain = $mapData['terrain'];
	
	echo "<script type=\"text/javascript\">
	$(function() {
		var cellCount = ".$totalCells.";
		var terrainSrc = '".$bgTerrain."';
		for (var i = 0; i < cellCount; i++) {
			$('#field').append('<img id=\"bgTile' + i + '\" class=\"background\" src=\"../images/terrain/' + terrainSrc + '\" />');
		}
	
	}";		
		
				
	echo ");
	
</script>";

?>

<style rel="stylesheet" type="text/css">
	#field {
		position: relative;
		width: <?php echo $totalMapWidth; ?>px;
		height: <?php echo $totalMapHeight; ?>px;
		background-color: #5054F4;
	}
	.props {
		z-index: 10;
	}
	.background {
		z-index: 1;
	}
</style>
</head>
<body>
<div id="field">
<?php

	for ($b = 0; $b < 26; $b++) {
		$xOffset = 'X'.$b;
		$yOffset = 'Y'.$b;
		$nameOffset = 'prop'.$b;
		
		if (($mapData[$nameOffset] == "none") || ($mapData[$xOffset] == -1) || ($mapData[$yOffset] == -1)) {
			
		} else {
			echo "<img id=\"prop".$b."\" class=\"props\" style=\"position: absolute; top: ".$mapData[$yOffset]."; left: ".$mapData[$xOffset].";\" src=\"../images/".$mapData[$nameOffset]."\" />";
		}		
	}

?>
</div>


</body>
</html>
connect.php (replace with your values):

Code: Select all

<?php

//////Get reference to DB
$db = mysqli_connect("localhost", "database", "password" ) or die("Could not obtain initial connection");
if(!$db) {
    echo "No connection obtained";
	exit;
}

if (!mysqli_select_db($db, "database")){
	echo "Could not select database";
	exit;
}

?>
The indelible lord of tl;dr
User avatar
Jackolantern
Posts: 10891
Joined: Wed Jul 01, 2009 11:00 pm

Re: Open Source PBBG World Builder -released-

Post by Jackolantern »

Screenshots:

First loading the editor
Image

Selecting terrain
Image

Making a sample map
Image

Map saved to the database
Image
The indelible lord of tl;dr
User avatar
hallsofvallhalla
Site Admin
Posts: 12023
Joined: Wed Apr 22, 2009 11:29 pm

Re: Open Source PBBG World Builder -released-

Post by hallsofvallhalla »

whoa this is nice man! I will test it out tomorrow
User avatar
Jackolantern
Posts: 10891
Joined: Wed Jul 01, 2009 11:00 pm

Re: Open Source PBBG World Builder -released-

Post by Jackolantern »

Ruh-roh lol. I had not tried any really large props, and the offset to make the cursor place the props near the middle of where you click (the way you would think it would work) was no represented in the code to save to the database, so larger objects aren't placed right. I will work on it early tomorrow and get it corrected, and possibly get an un-do feature working. Working on some maps this evening showed me how badly I needed it.
The indelible lord of tl;dr
User avatar
Jackolantern
Posts: 10891
Joined: Wed Jul 01, 2009 11:00 pm

Re: Open Source PBBG World Builder -released-

Post by Jackolantern »

Tomorrow? Ha! I should have known my OCD would make me fix it tonight lol. I added in the aiming reticle that follows your mouse when in the map. It creates a floating box that represents the size of the image on the map. It actually allows for much more precision placement of props now.

Here is the new code, but I will also update it above so no one uses the wrong version.

Note:*****Newer version (v.0.4.10) below*****

worldbuilder.php:

Code: Select all

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>World Builder</title>
<meta name="" content="">
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
<script type="text/javascript" src="../js/jquery141.js"></script>
<?php 
	echo '<script type="text/javascript">
	var propSize = '.$_GET['terrainwidth'].';
	var mapWidth = '.$_GET['mapwidth'].';
	var mapHeight = '.$_GET['mapheight'].';
</script>';
?>
<script type="text/javascript">
	$(function() {
		/* =====  PBBG World Builder v.0.3.3 =====
		*  created Nov 18, 2010   copyright 2010 Tim Crouch
		*  Released under the MIT license http://www.opensource.org/licenses/mit-license.php
		*/
		
		
		//used to fill the field in the World Builder
		var terrainChoice = '';
		//the associative array to hold the image names (aka filenames) and their x and y locations (stored as a ordered pair)
		var propLocations = new Array();
		//used to hold the current prop choice as a path file. Used to display on the field and to send through AJAX
		var currentProp = '';
		//a variable to keep a count of how many props have been placed
		var propCount = 0;
		//2 variables to hold the size of the chosen element
		var theElementX = 24;
		var theElementY = 24;
		
		//hide the aiming div until needed
		$('#aiming').hide();
		
		//the event handler for clicking on a prop image
		$('.prop').click(function(evnt) {
			//display the current selection under the map in the "currently selected" icon
			var currentImgSrc = $(evnt.target).attr('src');
			$('#currentDiv').html('<img id="currentImg" src="' + currentImgSrc + '" />');
			
			//store the prop's file path for use to display on the field
			currentProp = currentImgSrc;
			
		});
		
		//track mouse movement in the field 
		$('#board').click(function(pos) {
			//Make sure a prop is selected before doing anything, and make sure no more than 25 props are added
			if ((currentProp != '') && (propCount <= 25)) {
				//get the x and y values of mouse click minus the offset of the field
				var xVal = pos.pageX - this.offsetLeft;
				var yVal = pos.pageY - this.offsetTop;
				$('#mouseLocation').html('X: ' + xVal + ' Y: ' + yVal);
				
				//%%%%%%%Begin process of adding the prop to the board%%%%%%%%%%%%%%%%%
				//increase propCount by one to show one more prop added to the field				
				$('#propCounter').html('Props: ' + propCount + '/25');
				
				//Adjust for pointer differences
				xVal = xVal + 9;
				yVal = yVal + 9;
				
				
				$('#board').append('<img id="prop' + propCount + '" class="setProp" style="position: absolute; left: ' + xVal + 'px; top: ' + yVal + 'px;" src="' + currentProp + '" />' );
				
				//%%%%%%%%ADD THE PROP FILENAME AND LOCATION TO THE propLocations ARRAY%%%%%%%%
				var myPropArray = currentProp.split('/');
				var propName = myPropArray[2];
				//CHANGED ';' to ':' temporarily
				propLocations['prop' + propCount] = xVal + ' ' + yVal + ' ' + propName;
				$('#propnumber').html(propLocations['prop' + propCount]);	
				
				propCount++;			
				
			}
			
		});
		
		//Add event handler for the mouse movement to add a placing cell for movement
		$('#board').mousemove(function(evnt) {
			$('#aiming').attr('style', 'position: absolute; width: ' + theElementX + '; height: ' + theElementY + '; left: ' + evnt.pageX + '; top: ' + evnt.pageY + ';');
			
		});
		
		//Show the aiming div when the mouse enters the board
		$('#board').mouseenter(function() {
			$('#board').append('<div id="aiming" style="position: absolute; width: ' + theElementX + '; height: ' + theElementY + '; left: 10; top: 10;"');
			theElementX = $('[src="' + currentProp + '"]').width();
			theElementY = $('[src="' + currentProp + '"]').height();	
		});
		
		//Hide the aiming reticle when the mouse exits the board
		$('#board').mouseleave(function() {
			$('#aiming').remove();
		});
		
		//event handler for clicking on a terrain texture
		$('.terrain').click(function(evnt) {
			//remove any texture that may already be there
			$('.backgroundTile').remove();
		
			//get the terrain image src
			var terrainSrc = $(evnt.target).attr('src');
			//alert('Selected a terrain texture. Src: ' + terrainSrc);
			
			//Figure out how many cells need to be filled
			var fillAmount = mapHeight * mapWidth; 
			
			
			//add the images for the background
			for (var count = 0; count < fillAmount; count++) {
				$('#board').append('<img id="backgroundTile' + count + '" class="backgroundTile" src="' + terrainSrc + '" />');
			}
			
			//split the terrain file path to get the file name alone
			var terrainArray = terrainSrc.split('/');
			
			//terrainChoice = myTerrainArray[3];
			terrainChoice = terrainArray[3];
			
		});
		
		//the event handler for the Save Map button
		$('#saveButton').click(function(evnt) {
			//extract values from the save fields
			var mapNameValue = $('#mapname').val();
			var zoneName = $('#zonename').val();
			var mapXCoord = $('#mapxcoord').val();
			var mapYCoord = $('#mapycoord').val();
			//$('#propnumber').html('Map name: ' + mapNameValue + '__ Map X: ' + mapXCoord + '__ Map Y: ' + mapYCoord);
			
			//Fill in any unused prop slots
			for (var fill = 0; fill < 26; fill++) {
				if (propLocations['prop' + fill] === undefined) {
				//if (!(propLocations['prop' + fill])) {
					propLocations['prop' + fill] = 'none';
				}
			}
			
			//Add the rest of the data to the array to be passed to the server
			propLocations['name'] = mapNameValue;
			propLocations['zone'] = zoneName;
			propLocations['mapx'] = mapXCoord;
			propLocations['mapy'] = mapYCoord;
			
			//send the data to the saveworld.php file through an AJAX post call				
			$.post('saveworld.php', {
					name: propLocations['name'],
					zone: propLocations['zone'],
					mapx: propLocations['mapx'],
					mapy: propLocations['mapy'],
					terrain: terrainChoice,
					terrainwidth: propSize,
					cellwidth: mapWidth,
					cellheight: mapHeight,
					prop0: propLocations['prop0'], prop1: propLocations['prop1'], prop2: propLocations['prop2'], prop3: propLocations['prop3'], prop4: propLocations['prop4'], prop5: propLocations['prop5'], prop6: propLocations['prop6'], prop7: propLocations['prop7'], prop8: propLocations['prop8'], prop9: propLocations['prop9'], prop10: propLocations['prop10'], prop11: propLocations['prop11'], prop12: propLocations['prop12'], prop13: propLocations['prop13'], prop14: propLocations['prop14'], prop15: propLocations['prop15'], prop16: propLocations['prop16'], prop17: propLocations['prop17'], prop18: propLocations['prop18'], prop19: propLocations['prop19'], prop20: propLocations['prop20'], prop21: propLocations['prop21'], prop22: propLocations['prop22'], prop23: propLocations['prop23'], prop24: propLocations['prop24'], prop25: propLocations['prop25']					 
				}, function(data) {
					if (data == 'success') {
						alert('Map saved to the database.');
					} else {
						alert('An error occured.');
					}					
				}
			);
			
			
			
		});
		
		$('#testButton').click(function() {		
			alert('X: ' + theElementX + ' Y: ' + theElementY);	
			//$('#testConsole').html('Terrain variable: ' + terrainChoice);
		});
	});
</script>
<?php
	//pull the previous form values from the URL and get them ready to size the div in the CSS
	$terrainTexture = $_GET['terrainwidth'];
	$mapHeight = $_GET['mapheight'];
	$mapWidth = $_GET['mapwidth'];
	
	//the actual div dimensions are the products of the terrain pixels by the number of cells desired
	$mapHeightPixels = $terrainTexture * $mapHeight;
	$mapWidthPixels = $terrainTexture * $mapWidth;
?>
<style rel="stylesheet" type="text/css">
	#board {
		position: relative;
		width: <?php echo $mapWidthPixels; ?>px;
		height: <?php echo $mapHeightPixels; ?>px;
		background-color: #5054F4;
		/*float: left;*/
	}
	#imagesSelector, #terrainsSelector {
		padding: 10px;
		margin: 10px;
		border: 2px solid #000000;
	}
	.backgroundTile {
		z-index: 1;
	}
	.setProp {
		z-index: 10;
	}
	#aiming{
		border: 1px solid #000000;
	}
		
	
</style>


</head>
<body>
<div id="main">
<div id="board">
</div>

<div class="clear" id="diagnostics">
	Currently selected:<br />
	<div id="currentDiv"></div><br />
	<!--TESTING***********************************-->
	<div id="mouseLocation"></div><br />
	<!--TESTING***********************************-->
	<div id="propnumber"></div>
	<div id="propCounter">Props: 0</div>
	<!--TESTING***********************************-->
	<div id="testConsole"></div>
</div>
</div>

<div id="imagesSelector">
Prop Icons <br />
<?php
	//pull up all the images up folder up, then into the images folder
	$files = glob("../images/*.*");
	for ($i = 1; $i < count($files); $i++) {
		$imgsrc = $files[$i];
		echo '<img id="'.$imgsrc.'" class="prop" src="'.$imgsrc.'" alt="random image" />';
	}
?>
</div>


<div id="terrainsSelector">
Terrain Choice <br />
<?php
	//pull up all the terrain images one folder up, then into the images folder, then into the terrain folder
	$files = glob("../images/terrain/*.*");
	for ($i = 1; $i < count($files); $i++) {
		$imgsrc = $files[$i];
		echo '<img id="'.$imgsrc.'" class="terrain" src="'.$imgsrc.'" alt="random image" />';
	}
?>
</div><br />
Name of map: <br />
<input type="text" id="mapname" size="25" /><br /><br />
Name of zone: <br />
<input type="text" id="zonename" size="25" /><br /><br />
X coordinate of map:<br />
<input type="text" id="mapxcoord" size="5" /><br />
Y coordinate of map:<br />
<input type="text" id="mapycoord" size="5" /><br />
<input type="submit" id="saveButton" value="Save Map" />
<!--TESTING***********************************************************-->
<input type="submit" id="testButton" value="Test Button" />




</body>
</html>
The indelible lord of tl;dr
Baseball435
Posts: 548
Joined: Sun May 30, 2010 3:49 am

Re: Open Source PBBG World Builder -released-

Post by Baseball435 »

wow thats great. NICE JOB!
Post Reply

Return to “Project Showoff Tier II”