网速测试工具编写

一、网速的测速原理为计算上传某一大小文件和下载某一大小文件时:

速度=大小/时间

二、误差影响多种:

网络环境(包括dns、执行脚本所需时间(包括服务器,客户端)、精细情况下,还包括文件头得相关信息。。。)、本地环境(不解释)

特别需要注意 gzip

 

三、设计:

1.把文件上传分两步来执行。第一步空上传。得到所需时间.

2.生成指定大小长度的文件,如:1024000长的字符串.

3.进行二次提交。后者时间减去第一次空上传的时间。得到1024000所需的实际时间。估算出上传的速度。

4.因为各种因素干扰。重复提交3~5次。取平均值。即当前客户端相对服务器的网速。

5.gzip解决方式(压缩算法大都是对相同内容进行压缩)

压缩过的文件。本身不容易再压缩,如jpg之类文件,测试下载,可以通过直接输出个定长的jpg文件。测试即可.

四、考虑网络不稳定:

1.剔除负值(头次请求高,二次请求慢,就会出现)

2.设置一个误差值。如 :30% 将多次的结果平均化,超过这误差值的结果剔除。再计算平均。

五、优化

1.使用swfupload 直接解析出上传时间。相对较准。

 

 

【转】265行代码实现第一人称游戏引擎 + 个人详细注解

http://www.php100.com/html/it/mobile/2014/0612/6971.html

玩才是学习的动力

背景分析

//一个圆圈弧度
//用来识别用户可视弧度 等等,绘制skybox时做图片截取处理.
var CIRCLE = Math.PI * 2;
var MOBILE = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i
		.test(navigator.userAgent)
function Controls() {
	this.codes = {
		37 : 'left',
		39 : 'right',
		38 : 'forward',
		40 : 'backward'
	};
	this.states = {
		'left' : false,
		'right' : false,
		'forward' : false,
		'backward' : false
	};
	document.addEventListener('keydown', this.onKey.bind(this, true), false);
	document.addEventListener('keyup', this.onKey.bind(this, false), false);
	document.addEventListener('touchstart', this.onTouch.bind(this), false);
	document.addEventListener('touchmove', this.onTouch.bind(this), false);
	document.addEventListener('touchend', this.onTouchEnd.bind(this), false);
}

Controls.prototype.onTouch = function(e) {
	var t = e.touches[0];
	this.onTouchEnd(e);
	if (t.pageY < window.innerHeight * 0.5)
		this.onKey(true, {
			keyCode : 38
		});
	else if (t.pageX < window.innerWidth * 0.5)
		this.onKey(true, {
			keyCode : 37
		});
	else if (t.pageY > window.innerWidth * 0.5)
		this.onKey(true, {
			keyCode : 39
		});
};

Controls.prototype.onTouchEnd = function(e) {
	this.states = {
		'left' : false,
		'right' : false,
		'forward' : false,
		'backward' : false
	};
	// 关闭默认事件
	e.preventDefault();
	// 关闭事件传递
	e.stopPropagation();
};

Controls.prototype.onKey = function(val, e) {
	var state = this.codes[e.keyCode];
	if (typeof state === 'undefined')
		return;
	this.states[state] = val;
	e.preventDefault && e.preventDefault();
	e.stopPropagation && e.stopPropagation();
};

function Bitmap(src, width, height) {
	this.image = new Image();
	this.image.src = src;
	this.width = width;
	this.height = height;
}
/**
 * 
 * @param x
 *            坐标
 * @param y
 *            坐标
 * @param direction
 *            方向
 * @returns {Player}
 */
function Player(x, y, direction) {
	this.x = x;
	this.y = y;
	this.direction = direction;
	// 武器
	this.weapon = new Bitmap('knife_hand.png', 319, 320);
	this.paces = 0;
}

/**
 * 旋转
 * 
 * @param angle
 *            角度
 */
Player.prototype.rotate = function(angle) {
	// 方向
	this.direction = (this.direction + angle + CIRCLE) % (CIRCLE);
};
/**
 * @param distance
 *            距离
 */
Player.prototype.walk = function(distance, map) {
	var dx = Math.cos(this.direction) * distance;
	var dy = Math.sin(this.direction) * distance;
	if (map.get(this.x + dx, this.y) <= 0)
		this.x += dx;
	if (map.get(this.x, this.y + dy) <= 0)
		this.y += dy;
	this.paces += distance;
};

Player.prototype.update = function(controls, map, seconds) {
	if (controls.left)
		this.rotate(-Math.PI * seconds);
	if (controls.right)
		this.rotate(Math.PI * seconds);
	if (controls.forward)
		this.walk(3 * seconds, map);
	if (controls.backward)
		this.walk(-3 * seconds, map);
};

function Map(size) {
	// 地区大小
	this.size = size;
	// 地区网格大小
	this.wallGrid = new Uint8Array(size * size);
	// 天空画布大小
	this.skybox = new Bitmap('deathvalley_panorama_sky.jpg', 4000, 1290);
	// 墙体画布大小
	this.wallTexture = new Bitmap('wall_texture.jpg', 1024, 1024);
	this.light = 0;
}

Map.prototype.get = function(x, y) {
	x = Math.floor(x);
	y = Math.floor(y);
	if (x < 0 || x > this.size - 1 || y < 0 || y > this.size - 1)
		return -1;
	return this.wallGrid[y * this.size + x];
};

Map.prototype.randomize = function() {
	for ( var i = 0; i < this.size * this.size; i++) {
		this.wallGrid[i] = Math.random() < 0.3 ? 1 : 0;
	}
};
/**
 * @point
 * @angle
 * @range 范围
 */
Map.prototype.cast = function(point, angle, range) {
	var self = this;
	var sin = Math.sin(angle);
	var cos = Math.cos(angle);
	var noWall = {
		length2 : Infinity
	};

	return ray({
		x : point.x,
		y : point.y,
		height : 0,
		distance : 0
	});

	function ray(origin) {
		var stepX = step(sin, cos, origin.x, origin.y);
		var stepY = step(cos, sin, origin.y, origin.x, true);
		var nextStep = stepX.length2 < stepY.length2 ? inspect(stepX, 1, 0,
				origin.distance, stepX.y) : inspect(stepY, 0, 1,
				origin.distance, stepY.x);

		if (nextStep.distance > range)
			return [ origin ];
		return [ origin ].concat(ray(nextStep));
	}

	function step(rise, run, x, y, inverted) {
		if (run === 0)
			return noWall;
		var dx = run > 0 ? Math.floor(x + 1) - x : Math.ceil(x - 1) - x;
		var dy = dx * (rise / run);
		return {
			x : inverted ? y + dy : x + dx,
			y : inverted ? x + dx : y + dy,
			length2 : dx * dx + dy * dy
		};
	}

	function inspect(step, shiftX, shiftY, distance, offset) {
		var dx = cos < 0 ? shiftX : 0;
		var dy = sin < 0 ? shiftY : 0;
		step.height = self.get(step.x - dx, step.y - dy);
		step.distance = distance + Math.sqrt(step.length2);
		if (shiftX)
			step.shading = cos < 0 ? 2 : 0;
		else
			step.shading = sin < 0 ? 2 : 1;
		step.offset = offset - Math.floor(offset);
		return step;
	}
};

/**
 * 模拟闪电的时间间隔 this.light 为当前地区的亮度值
 */
Map.prototype.update = function(seconds) {
	return;
	if (this.light > 0)// 按时间把亮度调低.当为最暗时,用0表示
		this.light = Math.max(this.light - 10 * seconds, 0);
	else if (Math.random() * 5 < seconds)
		this.light = 2;// 按某概率 出现闪电
};

function Camera(canvas, resolution, fov) {
	// 画布
	this.ctx = canvas.getContext('2d');
	// 通过style 将 画面强制放大,填充屏幕。画面越精细,速度越慢,反之则画面模糊,但是速度快。默认大小为0.5
	this.width = canvas.width = window.innerWidth * 0.5;
	this.height = canvas.height = window.innerHeight * 0.5;

	this.resolution = resolution;
	this.spacing = this.width / resolution;
	// 视角 为固定 0.4*pi
	this.fov = fov;
	this.range = MOBILE ? 8 : 14;
	this.lightRange = 5;
	//
	this.scale = (this.width + this.height) / 1200;
}

Camera.prototype.render = function(player, map) {
	// 单纯只是计算出闭合后。图片的相关特征,做背景
	this.drawSky(player.direction, map.skybox, map.light);
	// 重点计算
	// this.drawColumns(player, map);
	// 玩家武器图,只是 一张晃动的图
	// this.drawWeapon(player.weapon, player.paces);
};
/**
 * direction 方向 (摄像头[用户角度方向]) sky 天空元素 (闭合状态下[图,首尾相连,形成的一圈为360度,即2*pi=CIRCLE ]。)
 * ambient 环境 (遮罩层,用来降低光线)
 */
Camera.prototype.drawSky = function(direction, sky, ambient) {
	// 计算出当前背景图的可视范围 this.fov(可视范围)
	// 不清楚这里的计算原理。
	var width = this.width * (CIRCLE / this.fov); // 2/0.4
	// 旋转偏角 图片左边的部分偏移
	// 宽度 direction 为当前视角弧度
	var left = -width * direction / CIRCLE;
	this.ctx.save();
	this.ctx.drawImage(sky.image, left, 0, width, this.height);
	if (left < width - this.width) {
		// console.log(left,direction / CIRCLE);
		this.ctx.drawImage(sky.image, left + width, 0, width, this.height);
	}
	// 一个遮罩层。让背景变亮或暗 , 即 map.ligth 配合闪电,做地面的渲染处理
	if (ambient > 0) {
		this.ctx.fillStyle = '#ffffff';
		this.ctx.globalAlpha = ambient * 0.1;
		this.ctx.fillRect(0, this.height * 0.5, this.width, this.height * 0.5);
	}
	this.ctx.restore();
};

Camera.prototype.drawColumns = function(player, map) {
	this.ctx.save();
	for ( var column = 0; column < this.resolution; column++) {
		var angle = this.fov * (column / this.resolution - 0.5);
		var ray = map.cast(player, player.direction + angle, this.range);
		this.drawColumn(column, ray, angle, map);
	}
	this.ctx.restore();
};

Camera.prototype.drawWeapon = function(weapon, paces) {
	var bobX = Math.cos(paces * 2) * this.scale * 6;
	var bobY = Math.sin(paces * 4) * this.scale * 6;
	var left = this.width * 0.66 + bobX;
	var top = this.height * 0.6 + bobY;
	this.ctx.drawImage(weapon.image, left, top, weapon.width * this.scale,
			weapon.height * this.scale);
};

Camera.prototype.drawColumn = function(column, ray, angle, map) {
	var ctx = this.ctx;
	var texture = map.wallTexture;
	var left = Math.floor(column * this.spacing);
	var width = Math.ceil(this.spacing);
	var hit = -1;

	while (++hit < ray.length && ray[hit].height <= 0)
		;

	for ( var s = ray.length - 1; s >= 0; s--) {
		var step = ray[s];
		var rainDrops = Math.pow(Math.random(), 3) * s;
		var rain = (rainDrops > 0) && this.project(0.1, angle, step.distance);

		if (s === hit) {
			var textureX = Math.floor(texture.width * step.offset);
			var wall = this.project(step.height, angle, step.distance);

			ctx.globalAlpha = 1;
			ctx.drawImage(texture.image, textureX, 0, 1, texture.height, left,
					wall.top, width, wall.height);

			ctx.fillStyle = '#000000';
			ctx.globalAlpha = Math.max((step.distance + step.shading)
					/ this.lightRange - map.light, 0);
			ctx.fillRect(left, wall.top, width, wall.height);
		}

		ctx.fillStyle = '#ffffff';
		ctx.globalAlpha = 0.15;
		while (--rainDrops > 0)
			ctx.fillRect(left, Math.random() * rain.top, 1, rain.height);
	}
};

Camera.prototype.project = function(height, angle, distance) {
	var z = distance * Math.cos(angle);
	var wallHeight = this.height * height / z;
	var bottom = this.height / 2 * (1 + 1 / z);
	return {
		top : bottom - wallHeight,
		height : wallHeight
	};
};

function GameLoop() {
	this.frame = this.frame.bind(this);
	this.lastTime = 0;
	this.callback = function() {
	};
}

GameLoop.prototype.start = function(callback) {
	this.callback = callback;
	requestAnimationFrame(this.frame);
};

GameLoop.prototype.frame = function(time) {
	var seconds = (time - this.lastTime) / 1000;
	this.lastTime = time;
	if (seconds < 0.2)
		this.callback(seconds);
	requestAnimationFrame(this.frame);
};

var display = document.getElementById('display');
var player = new Player(15.3, -1.2, Math.PI * 0.3);
var map = new Map(32);
var controls = new Controls();
var camera = new Camera(display, MOBILE ? 160 : 320, Math.PI * 0.4);
var loop = new GameLoop();

map.randomize();
// 系统自动循环时,自动调整时间 seconds 时间间隔长度 .
loop.start(function frame(seconds) {
	map.update(seconds);
	player.update(controls.states, map, seconds);
	camera.render(player, map);
});

武器分析

//一个圆圈弧度
//用来识别用户可视弧度 等等,绘制skybox时做图片截取处理.
var CIRCLE = Math.PI * 2;
var MOBILE = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i
		.test(navigator.userAgent)
function Controls() {
	this.codes = {
		37 : 'left',
		39 : 'right',
		38 : 'forward',
		40 : 'backward'
	};
	this.states = {
		'left' : false,
		'right' : false,
		'forward' : false,
		'backward' : false
	};
	document.addEventListener('keydown', this.onKey.bind(this, true), false);
	document.addEventListener('keyup', this.onKey.bind(this, false), false);
	document.addEventListener('touchstart', this.onTouch.bind(this), false);
	document.addEventListener('touchmove', this.onTouch.bind(this), false);
	document.addEventListener('touchend', this.onTouchEnd.bind(this), false);
}

Controls.prototype.onTouch = function(e) {
	var t = e.touches[0];
	this.onTouchEnd(e);
	if (t.pageY < window.innerHeight * 0.5)
		this.onKey(true, {
			keyCode : 38
		});
	else if (t.pageX < window.innerWidth * 0.5)
		this.onKey(true, {
			keyCode : 37
		});
	else if (t.pageY > window.innerWidth * 0.5)
		this.onKey(true, {
			keyCode : 39
		});
};

Controls.prototype.onTouchEnd = function(e) {
	this.states = {
		'left' : false,
		'right' : false,
		'forward' : false,
		'backward' : false
	};
	// 关闭默认事件
	e.preventDefault();
	// 关闭事件传递
	e.stopPropagation();
};

Controls.prototype.onKey = function(val, e) {
	var state = this.codes[e.keyCode];
	if (typeof state === 'undefined')
		return;
	this.states[state] = val;
	e.preventDefault && e.preventDefault();
	e.stopPropagation && e.stopPropagation();
};

function Bitmap(src, width, height) {
	this.image = new Image();
	this.image.src = src;
	this.width = width;
	this.height = height;
}
/**
 * 
 * @param x
 *            坐标
 * @param y
 *            坐标
 * @param direction
 *            方向
 * @returns {Player}
 */
function Player(x, y, direction) {
	this.x = x;
	this.y = y;
	this.direction = direction;
	// 武器
	this.weapon = new Bitmap('knife_hand.png', 319, 320);
	this.paces = 0;
}

/**
 * 旋转
 * 
 * @param angle
 *            角度
 */
Player.prototype.rotate = function(angle) {
	// 方向
	this.direction = (this.direction + angle + CIRCLE) % (CIRCLE);
};
/**
 * @param distance
 *            距离
 */
Player.prototype.walk = function(distance, map) {
	var dx = Math.cos(this.direction) * distance;
	var dy = Math.sin(this.direction) * distance;
	if (map.get(this.x + dx, this.y) <= 0)
		this.x += dx;
	if (map.get(this.x, this.y + dy) <= 0)
		this.y += dy;
	//前进的距离。步数
	//旋转不算
	this.paces += distance;
};

Player.prototype.update = function(controls, map, seconds) {
	if (controls.left)
		this.rotate(-Math.PI * seconds);
	if (controls.right)
		this.rotate(Math.PI * seconds);
	if (controls.forward)
		this.walk(3 * seconds, map);
	if (controls.backward)
		this.walk(-3 * seconds, map);
};

function Map(size) {
	// 地区大小
	this.size = size;
	// 地区网格大小
	this.wallGrid = new Uint8Array(size * size);
	// 天空画布大小
	this.skybox = new Bitmap('deathvalley_panorama.jpg', 4000, 1290);
	// 墙体画布大小
	this.wallTexture = new Bitmap('wall_texture.jpg', 1024, 1024);
	this.light = 0;
}

Map.prototype.get = function(x, y) {
	x = Math.floor(x);
	y = Math.floor(y);
	if (x < 0 || x > this.size - 1 || y < 0 || y > this.size - 1)
		return -1;
	return this.wallGrid[y * this.size + x];
};

Map.prototype.randomize = function() {
	for ( var i = 0; i < this.size * this.size; i++) {
		this.wallGrid[i] = Math.random() < 0.3 ? 1 : 0;
	}
};
/**
 * @point
 * @angle
 * @range 范围
 */
Map.prototype.cast = function(point, angle, range) {
	var self = this;
	var sin = Math.sin(angle);
	var cos = Math.cos(angle);
	var noWall = {
		length2 : Infinity
	};

	return ray({
		x : point.x,
		y : point.y,
		height : 0,
		distance : 0
	});

	function ray(origin) {
		var stepX = step(sin, cos, origin.x, origin.y);
		var stepY = step(cos, sin, origin.y, origin.x, true);
		var nextStep = stepX.length2 < stepY.length2 ? inspect(stepX, 1, 0,
				origin.distance, stepX.y) : inspect(stepY, 0, 1,
				origin.distance, stepY.x);

		if (nextStep.distance > range)
			return [ origin ];
		return [ origin ].concat(ray(nextStep));
	}

	function step(rise, run, x, y, inverted) {
		if (run === 0)
			return noWall;
		var dx = run > 0 ? Math.floor(x + 1) - x : Math.ceil(x - 1) - x;
		var dy = dx * (rise / run);
		return {
			x : inverted ? y + dy : x + dx,
			y : inverted ? x + dx : y + dy,
			length2 : dx * dx + dy * dy
		};
	}

	function inspect(step, shiftX, shiftY, distance, offset) {
		var dx = cos < 0 ? shiftX : 0;
		var dy = sin < 0 ? shiftY : 0;
		step.height = self.get(step.x - dx, step.y - dy);
		step.distance = distance + Math.sqrt(step.length2);
		if (shiftX)
			step.shading = cos < 0 ? 2 : 0;
		else
			step.shading = sin < 0 ? 2 : 1;
		step.offset = offset - Math.floor(offset);
		return step;
	}
};

/**
 * 模拟闪电的时间间隔
 * this.light 为当前地区的亮度值
 */
Map.prototype.update = function(seconds) {
	if (this.light > 0)//按时间把亮度调低.当为最暗时,用0表示 
		this.light = Math.max(this.light - 10 * seconds, 0);
	else if (Math.random() * 5 < seconds)
		this.light = 2;//按某概率 出现闪电
};

function Camera(canvas, resolution, fov) {
	// 画布
	this.ctx = canvas.getContext('2d');
	// 通过style 将 画面强制放大,填充屏幕。画面越精细,速度越慢,反之则画面模糊,但是速度快。默认大小为0.5
	this.width = canvas.width = window.innerWidth * 0.5;
	this.height = canvas.height = window.innerHeight * 0.5;

	//分辨率
	this.resolution = resolution;
	this.spacing = this.width / resolution;
	// 视角 为固定 0.4*pi
	this.fov = fov;
	this.range = MOBILE ? 8 : 14;
	this.lightRange = 5;
	//只用来识别武器的分变率。或者说,大小
	this.scale = (this.width + this.height) / 1200;
}

Camera.prototype.render = function(player, map) {
	// 单纯只是计算出闭合后。图片的相关特征,做背景
	this.drawSky(player.direction, map.skybox, map.light);
	// 重点计算
	this.drawColumns(player, map);
	// 玩家武器图,只是 一张晃动的图
	//旋转时不晃动。晃动的幅度根据当前前进的步数或者后腿时的步数
	this.drawWeapon(player.weapon, player.paces);
};
/**
 * direction 方向 (摄像头[用户角度方向]) sky 天空元素 (闭合状态下[图,首尾相连,形成的一圈为360度,即2*pi=CIRCLE ]。)
 * ambient 环境 (遮罩层,用来降低光线)
 */
Camera.prototype.drawSky = function(direction, sky, ambient) {
	// 计算出当前背景图的可视范围 this.fov(可视范围)
	//不清楚这里的计算原理。
	var width = this.width * (CIRCLE / this.fov);  // 2/0.4
	// 旋转偏角 图片左边的部分偏移
	// 宽度  direction 为当前视角弧度
	var left = -width * direction / CIRCLE;
	this.ctx.save();
	this.ctx.drawImage(sky.image, left, 0, width, this.height);
	if (left < width - this.width) {
		//console.log(left,direction / CIRCLE);
		this.ctx.drawImage(sky.image, left + width, 0, width, this.height);
	}
	if (ambient > 0) {
		this.ctx.fillStyle = '#ffffff';
		this.ctx.globalAlpha = ambient * 0.1;
		this.ctx.fillRect(0, this.height * 0.5, this.width, this.height * 0.5);
	}
	this.ctx.restore();
};

Camera.prototype.drawColumns = function(player, map) {
	this.ctx.save();
	for ( var column = 0; column < this.resolution; column++) {
		var angle = this.fov * (column / this.resolution - 0.5);
		var ray = map.cast(player, player.direction + angle, this.range);
		this.drawColumn(column, ray, angle, map);
	}
	this.ctx.restore();
};

Camera.prototype.drawWeapon = function(weapon, paces) {
	//利用cos 的正弦和余弦的波动范围为1至-1,加上对应的识别大小做抖动
	//模拟人走动时,摆动的弧度.曲线.
	var bobX = Math.cos(paces * 2) * this.scale * 6;
	var bobY = Math.sin(paces * 4) * this.scale * 6;
	var left = this.width * 0.66 + bobX;
	var top = this.height * 0.6 + bobY;
	this.ctx.drawImage(weapon.image, left, top, weapon.width * this.scale,
			weapon.height * this.scale);
};

Camera.prototype.drawColumn = function(column, ray, angle, map) {
	var ctx = this.ctx;
	var texture = map.wallTexture;
	var left = Math.floor(column * this.spacing);
	var width = Math.ceil(this.spacing);
	var hit = -1;

	while (++hit < ray.length && ray[hit].height <= 0)
		;

	for ( var s = ray.length - 1; s >= 0; s--) {
		var step = ray[s];
		var rainDrops = Math.pow(Math.random(), 3) * s;
		var rain = (rainDrops > 0) && this.project(0.1, angle, step.distance);

		if (s === hit) {
			var textureX = Math.floor(texture.width * step.offset);
			var wall = this.project(step.height, angle, step.distance);

			ctx.globalAlpha = 1;
			ctx.drawImage(texture.image, textureX, 0, 1, texture.height, left,
					wall.top, width, wall.height);

			ctx.fillStyle = '#000000';
			ctx.globalAlpha = Math.max((step.distance + step.shading)
					/ this.lightRange - map.light, 0);
			ctx.fillRect(left, wall.top, width, wall.height);
		}

		ctx.fillStyle = '#ffffff';
		ctx.globalAlpha = 0.15;
		while (--rainDrops > 0)
			ctx.fillRect(left, Math.random() * rain.top, 1, rain.height);
	}
};

Camera.prototype.project = function(height, angle, distance) {
	var z = distance * Math.cos(angle);
	var wallHeight = this.height * height / z;
	var bottom = this.height / 2 * (1 + 1 / z);
	return {
		top : bottom - wallHeight,
		height : wallHeight
	};
};

function GameLoop() {
	this.frame = this.frame.bind(this);
	this.lastTime = 0;
	this.callback = function() {
	};
}

GameLoop.prototype.start = function(callback) {
	this.callback = callback;
	requestAnimationFrame(this.frame);
};

GameLoop.prototype.frame = function(time) {
	var seconds = (time - this.lastTime) / 1000;
	this.lastTime = time;
	if (seconds < 0.2)
		this.callback(seconds);
	requestAnimationFrame(this.frame);
};

var display = document.getElementById('display');
var player = new Player(15.3, -1.2, Math.PI * 0.3);
var map = new Map(32);
var controls = new Controls();
var camera = new Camera(display, MOBILE ? 160 : 320, Math.PI * 0.4);
var loop = new GameLoop();

map.randomize();
//系统自动循环时,自动调整时间 seconds 时间间隔长度 .
loop.start(function frame(seconds) {
	map.update(seconds);
	player.update(controls.states, map, seconds);
	camera.render(player, map);
});

 

小试 javafx

安装:

http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html

引入:

jdkjrelibjfxrt.jar

demo

http://docs.oracle.com/javase/8/javafx/get-started-tutorial/get_start_apps.htm#JFXST804

浏览器demo

package helloworld;
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

public class WebViewSample extends Application {
	private Scene scene;

	@Override
	public void start(Stage stage) {
		// create the scene
		stage.setTitle("Web View");
		scene = new Scene(new Browser(), 750, 500, Color.web("#666970"));
		stage.setScene(scene);
		scene.getStylesheets().add("webviewsample/BrowserToolbar.css");
		stage.show();
	}

	public static void main(String[] args) {
		launch(args);
	}
}

class Browser extends Region {

	final WebView browser = new WebView();
	final WebEngine webEngine = browser.getEngine();

	public Browser() {
		// apply the styles
		getStyleClass().add("browser");
		// load the web page
		webEngine.load("http://blog.martoo.cn");
		getStyleClass().add("webviewsample/BrowserToolbar.css");
		// add the web view to the scene
		getChildren().add(browser);

	}

	private Node createSpacer() {
		Region spacer = new Region();
		HBox.setHgrow(spacer, Priority.ALWAYS);
		return spacer;
	}

	@Override
	protected void layoutChildren() {
		double w = getWidth();
		double h = getHeight();
		layoutInArea(browser, 0, 0, w, h, 0, HPos.CENTER, VPos.CENTER);
	}

	@Override
	protected double computePrefWidth(double height) {
		return 750;
	}

	@Override
	protected double computePrefHeight(double width) {
		return 500;
	}
}

 

scene.getStylesheets().add("webviewsample/BrowserToolbar.css");

相对当前包的根目录。

如:

/helloworld/WebViewSample.java

/webviewsample/BrowserToolbar.css

样式文件demo:

/src/helloworld/HelloWorld.java

package helloworld;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class HelloWorld extends Application {
	public static void main(String[] args) {
		launch(args);
	}

	@Override
	public void start(Stage primaryStage) {
		primaryStage.setTitle("Hello World!");
		Button btn = new Button();
		btn.setText("Say 'Hello World'");
		btn.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent event) {
				System.out.println("Hello World!");
			}
		});

		StackPane root = new StackPane();
		root.getChildren().add(btn);

		Scene scene = new Scene(root, 300, 250);

		scene.getStylesheets().add(
				HelloWorld.class.getResource("../test.css").toExternalForm());
		primaryStage.setScene(scene);
		primaryStage.show();
	}
}

/src/test.css

.root {
     -fx-background-image: url("background.jpg");
}
.label {
    -fx-font-size: 12px;
    -fx-font-weight: bold;
    -fx-text-fill: #333333;
    -fx-effect: dropshadow( gaussian , rgba(255,255,255,0.5) , 0,0,0,1 );
}
.button {
    -fx-font-size: 19px;
    -fx-font-weight: bold;
    -fx-text-fill: #333333;
    -fx-effect: dropshadow( gaussian , rgba(255,255,255,0.5) , 0,0,0,1 );
}

 

 

编写 PHP 为程序逻辑代码的 SWING客户端

首先,需要确保目的程序 ,php能独立执行。能输出。

纯粹只是因为用java写复杂逻辑代码比较蛋疼,或者说,因为有现成的代码是php的,重写需要花大量的时间。所以以java 的命令形式进行调用。

步骤 :

1.php代码一份

2.php运行环境一份

2.1 如果非指定形式调用。默认配置文件需要为 : php.ini ,不能有别名

2.2 配置内部内容需要清理不必要的配置,引用路径调整

2.3 单独执行一个文件,调整到不出问题,能正常执行为止

c:ooxxphp.exe “c:aabbindex.php”

3.用java Swing 绘制一个壳,用myeclipse ,前提需要有java 基础,或类似的winform基础比较容易上手,不然适当进行学习即可.

4.用exe4j 打包

参考:http://blog.martoo.cn/?p=613

 

补充相关代码:

一、命令调用

try {
			String php_exe = System.getProperty("user.dir")
					+ "/php/php/php.exe";
			String php_file = System.getProperty("user.dir")
					+ "/php/exec.php";
			if (!filexists(php_exe)) {
				JOptionPane.showMessageDialog(null,
						"The php.exe file is not exist");
				System.exit(0);
			}
			if (!filexists(php_file)) {
				JOptionPane
						.showMessageDialog(null, "The php file is not exist");
				System.exit(0);
			}

			String shell = php_exe + " "" + php_file + """;
			Process ps = Runtime.getRuntime().exec(shell);
			ps.waitFor();
			BufferedReader br = new BufferedReader(new InputStreamReader(
					ps.getInputStream()));
			StringBuffer sb = new StringBuffer();
			String line;
			String contentempty = "";
			while ((line = br.readLine()) != null) {
				contentempty += line;
				sb.append(line).append("n");
			}
			String result = sb.toString();
			if (!contentempty.isEmpty()) {
				recordinfo(result);
				JOptionPane.showMessageDialog(null, result);
			}
		} catch (Exception e) {
			recordinfo(e.getMessage());
		}

 

 

	public static void recordinfo(String log) {
		String path = System.getProperty("user.dir") + "/php_log.txt";
		try {
			FileWriter fw = new FileWriter(path, true);
			PrintWriter pw = new PrintWriter(fw);
			pw.println(log);
			pw.close();
			// bw.close();
			fw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

 

public static boolean filexists(String filename) {
		return new File(filename).exists();
}

 

输出信息可直接用于弹出框提示。

也可以记录为日志。

二、通讯操作

使用java  properties

properties  保存和读取代码

Properties prop = new Properties();
			FileInputStream fis;
			FileOutputStream fos;
			try {
				fis = new FileInputStream(System.getProperty("user.dir")
						+ "/php/prop.properties");

				fos = new FileOutputStream(System.getProperty("user.dir")
						+ "/php/prop.properties");

				prop.load(fis);
				prop.setProperty("csvpath", jfc.getSelectedFile()
						.getAbsolutePath());
				prop.save(fos, " config file");
				// System.out.println(prop.getProperty("a"));
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

 

php 获取代码:

参考:http://blog.martoo.cn/?p=825

三:常用功能代码

文件选择框

JFileChooser jfc = new JFileChooser();
if (jfc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
        //获取路径
	System.out.println(jfc.getSelectedFile().getAbsolutePath());
}

弹出提示框

				JOptionPane
						.showMessageDialog(null, "The php file is not exist");

补充 : 意大利操作系统(win7 64x)关闭不了问题

	Process ps;
		try {
			ps = Runtime.getRuntime().exec("taskkill /f /im xxx.exe");
			ps.waitFor();
			BufferedReader br = new BufferedReader(new InputStreamReader(
					ps.getInputStream()));
			StringBuffer sb = new StringBuffer();
			String line;
			String contentempty = "";
			while ((line = br.readLine()) != null) {
				contentempty += line;
				sb.append(line).append("n");
			}
			String result = sb.toString();
			if (!contentempty.isEmpty()) {
				recordinfo(result);
				JOptionPane.showMessageDialog(null, result);
			}
		} catch (IOException e2) {
			e2.printStackTrace();
		} catch (InterruptedException xe) {
			xe.printStackTrace();
		}

 

转发请注明出处http://blog.martoo.cn
如有漏缺,请联系我 QQ 243008827

php get java properties fix(utf-8)

$properties = parse_properties ( 'prop.properties' );
var_export ( $properties );
function unicode2utf8($str) {
	if (! $str)
		return $str;
	$decode = json_decode ( $str );
	if ($decode)
		return $decode;
	$str = '["' . $str . '"]';
	$decode = json_decode ( $str );
	if (count ( $decode ) == 1) {
		return $decode [0];
	}
	return $str;
}
function parse_properties($propertiespath) {
	$txtProperties = file_get_contents ( $propertiespath );
	$result = array ();
	$lines = split ( "n", $txtProperties );
	$key = "";
	$isWaitingOtherLine = false;
	foreach ( $lines as $i => $line ) {
		if (empty ( $line ) || (! $isWaitingOtherLine && strpos ( $line, "#" ) === 0))
			continue;

		if (! $isWaitingOtherLine) {
			$key = substr ( $line, 0, strpos ( $line, '=' ) );
			$value = substr ( $line, strpos ( $line, '=' ) + 1, strlen ( $line ) );
		} else {
			$value .= $line;
		}
		/* Check if ends with single '' */
		if (strrpos ( $value, "" ) === strlen ( $value ) - strlen ( "" )) {
			$value = substr ( $value, 0, strlen ( $value ) - 1 ) . "n";
			$isWaitingOtherLine = true;
		} else {
			$isWaitingOtherLine = false;
		}
		$value = trim ( $value );
		$value = preg_replace ( "/(\uw{4})/e", "unicode2utf8('1')", $value );
		$value = preg_replace ( "/\\/", "", $value );
		$value = preg_replace ( "/\:/", ":", $value );
		$result [$key] = $value;
		unset ( $lines [$i] );
	}
	return $result;
}

转发请注明出处http://blog.martoo.cn
如有漏缺,请联系我 QQ 243008827

支付宝 错误代码 ILLEGAL_SIGN

签名异常,不解释。

静排查。可导入异常的参数有

body

subject

一开始以为长度限制,因为官方文档申明

body (string 1000)

subject (string 256)

截取,依旧出问题

经各种排查,发现问题原因为参数出现特殊字符。现提供特殊字符的过滤处理

处理一:

		$parameter['subject']=preg_replace('/s/', '', $parameter['subject']);
		$parameter['body']=preg_replace('/s/', '', $parameter['body']);

处理二:

		//限制提交字符长度
		//过滤特殊字符 s 否则识别有问题
		$parameter['subject']= preg_split('/[^())(【】.!!w+-*^x{4e00}-x{9fa5}]+/u', $parameter['subject']);
		$parameter['subject']=implode(' ', $parameter['subject']);
		$parameter['body']= preg_split('/[^())(【】.!!w+-*^x{4e00}-x{9fa5}]+/u', $parameter['body']);
		$parameter['body']=implode(' ', $parameter['body']);

转发请注明出处http://blog.martoo.cn
如有漏缺,请联系我 QQ 243008827

Sqlite 使用

官网:https://bitbucket.org/xerial/sqlite-jdbc

jar:https://bitbucket.org/xerial/sqlite-jdbc/downloads

mysql 转 sqlite 相关处理

基本上语法通用,需要特殊处理的有.

用navicat premium 导出两种数据库,比较后,需要处理的有

1. ` 全部替换成 ”

2.   类型只有 text integer blob real  这些。根据需要进行处理。

 

异常判断

encrypted sqlite db

如果用 navicat premium 打开正常,直接用记事本看下当前的 sqlite 的版本是多少.

这边的是php 5.2 默认的扩展是 sqlite 2.0

需要打开,然后做下转换处理.

blob类型取出时,被转码成

需要做特殊处理

stripcslashes()

这边只是普通的查询,具体情况自行判断.

转发请注明出处http://blog.martoo.cn
如有漏缺,请联系我 QQ 243008827