两年份懒人笔记…

find . -mtime 10 -name "*.php" ! -path "*cache*" ! -path "*think*" ! -path "*runtime*"
  搜索最近修改且排除目录
puppeteer 字体没有生效
  yum groupinstall "Font"
宝塔防火墙实现反响代理时提取真实IP进行安全验证
  宝塔防火墙中本身有CDN设置,开启会识别请求头中信息,有安全问题。识别具体反向服务器IP,再通过提取头部转发IP,才妥当
  /www/server/btwaf/httpd.lua
  function get_client_ip() 最后面补充下列语句
  if(client_ip=='反响代理服务器IP' and httpd.headers_in['x-forwarded-for']~= nil  and httpd.headers_in['x-forwarded-for'] ~= "")  then

		client_ip= httpd.headers_in['x-forwarded-for'];

	end
lua 使用模块
  yum install luarocks
  luarocks install inspect
  lua 文件中local inspect = require('inspect')引入
IE卸载 https://www.cnblogs.com/cang12138/p/6707307.html
统计apache 日志某天前100名
cat xxxxx | grep "16/Nov/2020"  |awk '{print $1}' | sort | uniq -c | sort -nr | head -100
  tail -n 1000000  xxxxxlog | cut -d ' ' -f 1 |sort |uniq -c | sort -nr | awk '{print $0 }' | head -n 10

lodash 按需安装
  npm install lodash.debounce
ssh 密钥登录
  https://toutiao.io/posts/popsg/preview
虚拟机网络不正常
  网络编辑器恢复默认
虚拟机VMware设置开机启动
  https://blog.51cto.com/4746316/2330911
  右键->管理->添加共享
  共享->设置->设置开机启动
oralce 触发器拦截插入
	IF :NEW.JKPT_UPLOAD_MODE in ('ADD','UPDATE') THEN

			raise_application_error ( -20101, '不允许  ADD,UPDATE' );

	END IF;
ubuntu 18 补充/etc/rc.local
  https://blog.csdn.net/qq_41782149/article/details/89001226
测试/etc/rc.local
  sudo /etc/rc.local
  观察当前会话和启动会话环境差异
  echo $PATH(两个地方输出看差异)
  export $PATH=$PATH:/xxxx(修正差异,避免开机启动时环境异常)
mysql 空用户名导致登录密码错误问题
  use mysql;delete from user where User='';  #删除账号为空的行
nodejs cluster 原理
  https://cnodejs.org/topic/56e84480833b7c8a0492e20c
mssql 多转义查询(每个查询后需要补充)
  where xx like '\_' escape '\' and xx not like '\_' escape '\' 
nsp内网穿透
  https://post.smzdm.com/p/az5emoon/
  https://ehang-io.github.io/nps/#/?id=nps
firewalld 命令
  https://wangchujiang.com/linux-command/c/firewall-cmd.html
端口转发软件(iptables,firewall 没启用...不敢直接开...)
  socat TCP4-LISTEN:12345,reuseaddr,fork TCP4:192.168.172.131:22
  后台运行:nohup xxxxx &
深入分析linux进程
  https://blog.csdn.net/FL63Zv9Zou86950w/article/details/105383294
  strace  php-fpm 输出进程所有执行过程
  pstack pid 跟踪进程
  vmstat 2 10 输出当前系统状态
  pidstat -w 5 查看进程上下文切换次数
  iostat -d -k 1 10
  -x 
svn版本 分支合并主线报缺失异常
  https://stackoverflow.com/questions/2472249/missing-ranges-error-message-when-reintegrating-a-branch-into-trunk-in-subversio
apache 日志分析神器
  apachetop 实时分析当前请求情况
  apachetop -f xxxx.log -T xxx 保留观察时间,默认30秒(方向键向右可查看地址的IP统计)
  goaccess 分析并导出日志分析内容, 非常全面
  goaccess 1000000.log  --log-format=COMBINED -o m.goaccess.html
sshfs sftp目录挂载 不补充参数会出现没有权限读取的问题
  sshfs -p 22 xxx@xxxxx.com:/ /xxxxx  -o allow_other -o reconnect
邮箱原理
  https://wiki.ubuntu.org.cn/IRedMail#iRedmail_.E7.BB.84.E4.BB.B6
剪切板过小问题
  修改系统虚拟内存.
查询window日志(按类型)
  https://blog.csdn.net/C_chuxin/article/details/84974207
php sftp 操作
  pear install 
  https://techglimpse.com/install-phpseclib-netssh2-netsftp-ppc64le-machine-centos/
  Net_SFTP 也可直接下载放到扩展,无需安装依赖.
  http://phpseclib.sourceforge.net/sftp/examples.html
phpstudy 新版本redis找不到, extention里后面少了.dll导致读取不到文件
  phpstudy 默认开启了opcache,需要关闭
mysql 复制表报错
  Specified key was too long, 索引键使用了utf8mb4导致
 puppeteer 安装 Failed to download Chromium r
 	cmd:set PUPPETEER_SKIP_DOWNLOAD=1  // 跳过chrome下载
  node ./node_modules/puppeteer/install.js // 单独下载谷歌
  record脚本:https://www.stefanjudis.com/blog/how-to-record-screen-actions-as-a-puppeteer-script/
  屏蔽特征:https://blog.xinshangshangxin.com/2019/01/01/headless-chrome-start/
svn 提交&清理报错  Failed to run the WC DB work queue associated with
  .svn/wc.db // sqlite3打开 清理WORK_QUEUE表(navicat 等工具直接打开操作即可)
redis消息订阅发布 https://www.runoob.com/redis/redis-pub-sub.html
  查询订阅状态 https://www.runoob.com/redis/pub-sub-pubsub.html
矩阵乘法证明
  http://www.ruanyifeng.com/blog/2015/09/matrix-multiplication.html
  https://nolaymanleftbehind.wordpress.com/2011/07/10/linear-algebra-what-matrices-actually-are/
pycharm " cv2 You need configured Python 2 SDK to render"
  file->setting->project->Python interpreter->齿轮->show all->添加python2.x进来(exsits environment)(python 3.x和python 2.0都要一起出现)
window 请求转发
打开cmd/powershell
首先安装IPV6(xp下IPV6必须安装,否则端口转发不可用!)
netsh interface ipv6 install
添加一个IPV4到IPV4的端口映射 (也可以直接不加listenaddress=0.0.0.0)
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=7000 connectaddress=目标IP connectport=7000
删除指定监听ip和端口
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=7000 
可以查看存在的转发
netsh interface portproxy show all
plsql 安装+导出,导入
  配置环境变量到oracle_home
  指定exp文件
firewall ipset 控制
  https://www.cnblogs.com/architectforest/p/12973982.html
php 调试
  phpstorm:file=>settings=>languages&frameworks=>php=>cli interpreter 添加php路径
  interpreter 指定 php 路径时, 下面的xdebug文件也需要指定
  对应php.ini配置xdebug为启用
SVN 版本误删除重新找回&合并(包括重命名)
  文件浏览器(右边指定浏览到达版本), 可显示该误删除分支原完整提交日志
  合并时指定版本范围,可合并原丢失SVN版本
yum socket代理 
  /etc/yum.conf  追加  socks5h://xxxx
gcc 编辑器版本升级
  手动编译:https://blog.csdn.net/EI__Nino/article/details/100086157
  https://gist.github.com/pablomp/237ee367e4a0ac060ed83d3d40e2285a
  find / -name "libstdc++.so*"
       检查编译后版本:strings /root/local/lib64/libstdc++.so.6.0.23 | grep CXXABI

       添加lib至全局:export LD_LIBRARY_PATH=/root/local/lib64/:$LD_LIBRARY_PATH

  安装式升级编辑器:https://linuxize.com/post/how-to-install-gcc-compiler-on-centos-7/
  复制文件到 /usr/lib64/xxx下
  建立软链接:ln -s libstdc++.so.6.0.25 libstdc++.so.6

 

拼音输入的检查

最近搞个东西需要能处理拼音检查功能,不处理英文检查。。

顺便提供一个拼写检查的工具

http://php.freehostingguru.com/group.php-4.php

不过这边要求比较低,只要检查出拼音是否输入错误。

考虑两个问题需要解决。

一:拼音是否强制代入了空格。

二:拼音是否可以不用输入空格。

实现思路

将以下字符串,循环比对,替换。不过需要注意一个东西,长的优先。否则替换会出问题。(自己手动写个正则处理下, 并按长度排序。)

a   ai   an   ang   ao
ba   bai   ban   bang   bao   bei   ben   beng   bi   bia   biao   bie   bin   bing   bo   bu
ca   cai   can   cang   cao   ce   cen   ceng   cha   chai   chan     chang   chao   che   chen   cheng   chi  chong  chou  chu  chua  chuai  chuan  chuang  chui  chun  chuo  ci  cong  cou  cu  cuan  cui  cun  cuo
da  dai  dan  dang  dao  de  dei  den  deng  di  dia  dian  diao  die  ding  diu  dong  dou  du  duan  dui  dun  duo
e  en  eng  er
fa  fan  fang  fei  fen  feng  fiao  fo  fou  fu
ga  gai  gan  gang  gao  ge  gei  gen  geng  gong  gou  gu  gua  guai  guan  guang  gui  gun  guo
ha  hai  han  hang  hao  he  hei  hen  heng  hong  hou  hu  hua  huai  huan  huang  hui  hun  huo
ji  jia  jian  jiang  jiao  jie  jin  jing  jiong  jiu  ju  juan  jue
ka  kai  kan  kang  kao  ke  ken  keng  kong  kou  ku  kua  kuai  kuan  kuang  kui  kun  kuo
la  lai  lan  lang  lao  le  lei  leng  li  lia  lian  liang  liao  lie  lin  ling  liu  lo  long  lou  lu  luan  lun  luo  lv  lve
ma  mai  man  mang  mao  me  mei  men  meng  mi  mian  miao  mie  min  ming  miu  mo  mou  mu
na  nai  nan  nang  nao  ne  nei  nen  neng  ni  nian  niang  niao  nie  nin  ning  niu  nong  nou  nu  nuan  nun  nuo  nv  nve
o  ou
pa  pai  pan  pang  pao  pei  pen  peng  pi  pian  piao  pie  pin  ping  po  pou  pu
qi  qia  qian  qiang  qiao  qie  qin  qing  qiong  qiu  qu  quan  que  qun
ran  rang  rao  re  ren  reng  ri  rong  rou  ru  rua  ruan  rui  run  ruo
sa  sai  san  sang  sao  se  sen  seng  sha  shai  shan  shang  shao  she  shei  shen  sheng  shi  shou  shu  shua  shuai  shuan  shuang  shui  shun  shuo  si  song  sou  su  suan  sui  sun  suo
ta  tai  tan  tang  tao  te  tei  teng  ti  tian  tiao  tie  ting  tong  tou  tu  tuan  tui  tun  tuo
wa  wai  wan  wang  wei  wen  weng  wo  wu
xi  xia  xian  xiang  xiao  xie  xin  xing  xiong  xiu  xu  xuan  xue  xun
ya  yan  yang  yao  ye  yi  yin  ying  yo  yong  you  yu  yuan  yue  yun
za  zai  zan  zang  zao  ze  zei  zen  zeng  zha  zhai  zhan  zhang  zhao  zhe  zhei  zhen  zheng  zhi  zhong  zhou  zhu  zhua  zhuai  zhuan  zhuang  zhui  zhun  zhuo  zi  zong  zou  zu  zuan  zui  zun  zuo

 

 

dodgepudding/wechat-php-sdk 添加登录验证码识别

其实有时间优化下,调整代码到 snoopy.class.php 用起来会方便点

Wechatext::getCode

	/**
	 * @添加验证码抓取.
	 */
	public function getCode() {
		$filename = $this->_cookiename;
		if (file_exists ( $filename )) {
			$mtime = filemtime ( $filename );
			if ($mtime < time () - $this->_cookieexpired)
				$data = '';
			else
				$data = file_get_contents ( $filename );
		} else
			$data = '';
		$send_snoopy = new Snoopy ();
		$send_snoopy->rawheaders ['Cookie'] = $data;
		$send_snoopy->maxredirs = 0;
		$url = "https://mp.weixin.qq.com/cgi-bin/verifycode?username=" . $this->_account . "&r=1406270984491";
		$send_snoopy->fetch ( $url );
		$cookie = '';
		foreach ( $send_snoopy->headers as $key => $value ) {
			$value = trim ( $value );
			if (preg_match ( '/^set-cookie:[s]+([^=]+)=([^;]+)/i', $value, $match ))
				$cookie .= $match [1] . '=' . $match [2] . '; ';
		}
		$this->saveCookie ( $this->_cookiename, $cookie );
		header ( 'Content-Type: image/jpeg' );
		echo $send_snoopy->results;
		exit ();
	}

补充验证码自动识别工具(不是做广告….)

http://www.uuwise.com/

注:微信对登录次数太多的ip做登录限制,会导致该ip的公众号无法登录。。慎玩。

网速测试工具编写

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

速度=大小/时间

二、误差影响多种:

网络环境(包括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);
});

 

编写 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