欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

使用HTML5和Google Maps构建手机LBS游戏 博客分类: Javascript游戏开发  

程序员文章站 2024-03-14 15:56:16
...

HTML5赋予Web开发人员更加强大的能力。其中的GeoLocation属性,可以让开发人员非常方便地获取用户的地理位置。结合Google Maps提供的API,就可以直观地在地图上将用户的位置标注出来。

今天带来的是我和Aj同学(博客)几个月前完成的一个小游戏。手机用户直接访问网址,即可参与该游戏。该游戏取材于经典的吃豆人游戏(Pac Man),所不同的是,玩家需要移动自己的真实的地理位置才能移动游戏中角色的位置。该游戏也支持多人对战,不同的玩家分别扮演吃豆人和鬼。

游戏的后端使用的是GAE。

先看模拟器上的截图:


1. 房间列表(index)


使用HTML5和Google Maps构建手机LBS游戏
            
    
    博客分类: Javascript游戏开发  

2. 创建游戏

 


使用HTML5和Google Maps构建手机LBS游戏
            
    
    博客分类: Javascript游戏开发  
 

3. 游戏进行中
使用HTML5和Google Maps构建手机LBS游戏
            
    
    博客分类: Javascript游戏开发  
 


现将开发中的一些心得,尤其是关于前端实现的心得,总结一下,以作抛砖引玉之用。


1. 如何自定义地图样式。

为了尽可能地和原作贴合,我们需要将地图绘制成黑底蓝条的模样,黑色代表可以通行的部分,蓝条代表“墙”或边界。所幸的是google maps已经提供给我们这个方法:



// 自定义地图样式,注意先后顺序不能调换
  var stylez = [
    {
      featureType: "all",
      stylers: [
        { hue: "#0000ff" },
        { saturation: 100 },
		{ lightness: -40}
      ]
    },
    {
      featureType: "road",
      stylers: [
        { hue: "#000000" },
        { saturation: 75 },
        { lightness: -100}
      ]
    }
  ];

var styledMapOptions = {
    name: "Pac Man"
  };
 
  // 设置地图类型
  var PacManMapType = new google.maps.StyledMapType(stylez, styledMapOptions);
  map.mapTypes.set(MY_MAPTYPE_ID, PacManMapType);


2. 如何获取玩家位置并显示在地图上
 

 

// 获取用户位置
	  navigator.geolocation.getCurrentPosition(function(position) {
			lastPos = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
			map.setCenter(lastPos);
			// 初始化地标
			origin = new google.maps.Marker({ 
				position: lastPos,
				map: map,
				draggable: true
			});
			
			addMarkerClickListener(origin, messages.prefix_ori);
			google.maps.event.trigger(origin, 'click');
			
		}, function() {
			alert(messages.geoservice_failed);
	  });

 

 那么如何做到实时更新用户的位置呢,也非常简单:


 

// 监听用户位置
	navigator.geolocation.watchPosition(function(position) {
			// 上传最新位置,不做任何事
			var curPos=new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
			var data='roomName='+roomInfo.roomName+'&location='+curPos.toUrlValue()+'&userName='+roomInfo.me;
			Ajax.post('updatelocation', data, function(){});
		}, function() {
			alert(messages.geoservice_failed);
		}, positionOptions);

 

 每当用户位置发生改变时,watchPosition将会被自动回调。


3. 如何在用户选定的出发点和目的地间均匀的绘制豆子。


 

// 绘制豆子
function drawBeans(){
	
	// 自定义地标图形
	var image = new google.maps.MarkerImage('./bean.png', null, null, new google.maps.Point(5, 5));
	
	var overview_path=directionsDisplay.getDirections().routes[0].overview_path;
	
	// 绘制豆子地标
	for(var i=1; i!=overview_path.length; ++i){
		var prev=overview_path[i-1];
		var next=overview_path[i];
		
		// 该路段的豆子数目,约数
		var count=Math.round(calcDistance(prev, next)/beanSpacing);
		for(var j=0; j!=count; ++j){
			var lat=prev.lat()+(next.lat()-prev.lat())*j/count;
			var lng=prev.lng()+(next.lng()-prev.lng())*j/count;
			var position = new google.maps.LatLng(lat, lng);
			
			var isExisted=false;
			for(var k=0; k!=beans.length; ++k){
				if(position.equals(beans[k].getPosition())){
					isExisted=true;
					break;
				}
			}
			
			if(!isExisted){
				var bean=new google.maps.Marker({
					position: position,
					map: map,
					icon: image
				});
				beans.push(bean);
			}
		}
	}

 

 overview_path是路线的一个属性。之所以使用routes[0],是因为同一个起点和终点间往往可能有不同的路径,通过下标指定为首选的那条路径。overview_path是一个数组,每个元素代表着该路径中的一个拐点,绘制路线其实就是将这些拐点连接起来。


然后,我们通过calcDistance函数计算前后拐点的距离,用这个值除以放置豆子的固定距离值,就可以得到该路段该绘制多少颗豆子,然后依次将这些豆子排布在拐点之间的连线上即可。

那么如何计算拐点间的距离呢?calcDistance的代码如下:


 

// 计算给定的两个latLng对象之间的距离, 返回单位为米
function calcDistance(pos1, pos2) {
	lat1=pos1.lat();
	lon1=pos1.lng();
	lat2=pos2.lat();
	lon2=pos2.lng();
	// m (change this constant to get km/miles etc.)
	var R = 6371 *1000; 
	var dLat = (lat2-lat1) * Math.PI / 180;
	var dLon = (lon2-lon1) * Math.PI / 180; 
	var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
		Math.cos(lat1 * Math.PI / 180 ) * Math.cos(lat2 * Math.PI / 180 ) * 
		Math.sin(dLon/2) * Math.sin(dLon/2); 
	var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
	var d = R * c;
	return Math.round(d);
}

 

 这里涉及到了一些地理和立体几何知识。当然,得到的只是一个近似值


4. 玩家状态的实时交互


很遗憾的是,这里使用的是Ajax轮询机制。Ajax工具代码如下,很简单:


 

Ajax={
	callback: null,
	url: null,
	
	ajaxErrorHandler: function(status, msg){
		alert('ajax failed due to '+status+' when fetch '+this.url);
	},
	
	get: function(url, func){
		this.url=url;
		this.callback=func;
		xmlhttp.open("GET", ajaxBaseUrl+url, true);
		xmlhttp.send();
	},
	
	post: function(url, data, func){
		this.url=url;
		this.callback=func;
		xmlhttp.open("POST", ajaxBaseUrl+url, true);
		xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
		xmlhttp.send(data);
	}
}

 

 

Aj同学做的关于websocket的毕设可以很好地解决实时性的问题。当然,还有诸如pushlet等替代技术,我们自己也没有实现,这里就不铺开讲述了。



最后,附上真机调试图和源代码,欢迎探讨。


测试设备是Hegar同学(博客)的moto defy。

 


使用HTML5和Google Maps构建手机LBS游戏
            
    
    博客分类: Javascript游戏开发  


使用HTML5和Google Maps构建手机LBS游戏
            
    
    博客分类: Javascript游戏开发  

 

  • 使用HTML5和Google Maps构建手机LBS游戏
            
    
    博客分类: Javascript游戏开发  
  • 大小: 49.4 KB
  • 使用HTML5和Google Maps构建手机LBS游戏
            
    
    博客分类: Javascript游戏开发  
  • 大小: 61 KB
  • 使用HTML5和Google Maps构建手机LBS游戏
            
    
    博客分类: Javascript游戏开发  
  • 大小: 8.4 KB
  • 使用HTML5和Google Maps构建手机LBS游戏
            
    
    博客分类: Javascript游戏开发  
  • 大小: 33.5 KB
  • 使用HTML5和Google Maps构建手机LBS游戏
            
    
    博客分类: Javascript游戏开发  
  • 大小: 20.2 KB