作者:禁止吸烟的禁

解决wordpress无法上传2M以上大文件大图片的方法

修改/etc/php.ini文件

upload_max_filesize = 128M 
post_max_size = 128M 
max_execution_time = 300 

重启apache服务

service php-fpm restart

如果报错:php-fpm.service not found 的话,可以查看服务器/etc/init.d/下面,对应的php的fpm名称,有时候会出现带版本好的情况,比如php7.2-fpm之类的,就执行

service php7.2-fpm restart

转:Unity相机跟随多种实现方式

转自:https://blog.csdn.net/qq_37310110/article/details/94007394

一:设置目标物为相机的父节点
描述:最简单,最基础,效果最不理想,锁死跟随视角

二:常规设置固定相对向量偏移
描述:推荐指数***,代码实现简,效果比较生硬

 public Transform target;
    private Vector3 offset;
    void Start()
    {
        //设置相对偏移
        offset = target.position - this.transform.position;
    }
    void Update()
    {
        //更新位置
        this.transform.position = target.position - offset;
    }

三:添加旋转角度
描述:推荐指数***,在二的基础上添加距离差值和旋转角度差值,效果流畅

   private Vector3 offset;//相机相对于玩家的位置
    public Transform target;
    private Vector3 pos;
    public float speed = 2;
    private void Start()
    {
        offset =  transform.position - target.position;
    }
    // Update is called once per frame
    void Update()
    {
        pos = target.position + offset;
        this.transform.position = Vector3.Lerp(transform.position, pos, speed * Time.deltaTime);//调整相机与玩家之间的距离

        Quaternion angel = Quaternion.LookRotation(target.position - transform.position);//获取旋转角度
        transform.rotation = Quaternion.Slerp(transform.rotation, angel, speed * Time.deltaTime);
    }
 

四: 第三背后视角
描述:推荐指数*****,流畅参数可调。对相机的位置实时计算

 public Transform target;
    public float distanceUp = 10f;//相机与目标的竖直高度参数
    public float distanceAway = 10f;//相机与目标的水平距离参数
    public float smooth = 2f;//位置平滑移动插值参数值
    public float camDepthSmooth = 20f;

    void Update()
    {
        // 鼠标轴控制相机的远近
        if ((Input.mouseScrollDelta.y < 0 && Camera.main.fieldOfView >= 3) || Input.mouseScrollDelta.y > 0 && Camera.main.fieldOfView <= 80)
        {
            Camera.main.fieldOfView += Input.mouseScrollDelta.y * camDepthSmooth * Time.deltaTime;
        }
    }

    void LateUpdate()
    {
        //计算出相机的位置
        Vector3 disPos = target.position + Vector3.up * distanceUp - target.forward * distanceAway;

        transform.position = Vector3.Lerp(transform.position, disPos, Time.deltaTime * smooth);
        //相机的角度
        transform.LookAt(target.position);
    }

五:自由 视角

using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;

public class target_control : MonoBehaviour {

    public Transform _target;
    public float distance = 50.0f;
    public float xSpeed = 250.0f;
    public float ySpeed = 120.0f;

    public int yMinLimit = -20;
    public int yMaxLimit = 80;

    private bool orbit = false;
    private bool pan = false;
    private bool zoom = false;
    private float zoomValue = 0;

    public float orbitDampX = 0.0f;
    public float orbitDampY = 0.0f;
    float panDampX = 0.0f;
    float panDampY = 0.0f;
    public float zoomDamp = 0.0f;
    public float dampingTime = 0.0f;

    public float x = 180.0f;
    public float y = 0.0f;

    public int planFactor = 5;
    public float zoomFactor = 2.0f;
    public Vector2 distLimit;

    public static Quaternion _rotation;
    public static Vector3 _position;
    public static target_control _target_control;
    public float _z_distance;
    private Vector3 angles;

    private Vector2 oldPosition1;   
    private Vector2 oldPosition2;

    public float _target_distance = 5;

    private float target_x;
    private float target_y;
    private Vector3 _target_pos = Vector3.zero;

    public bool change_distance() 
    {
        distance = Mathf.Lerp(distance, _target_distance, 0.04f);
        Debug.Log(distance + "/" + _target_distance);
        updateCamera();
        if (Mathf.Abs(distance - _target_distance) < 0.01f)
            return false;
        return true;
    }
    public bool change_distance(float _dis)
    {
        distance = Mathf.Lerp(distance, _dis, 0.004f);

        updateCamera();
        if (Mathf.Abs(distance - _dis) < 0.01f)
            return false;
        return true;
    }

    void Start()
    {
        _target_distance = distance;
        _z_distance = distance;
        angles = transform.eulerAngles;
        x = angles.y;
        y = angles.x;

        // Make the rigid body not change rotation
        if (GetComponent<Rigidbody>())
            GetComponent<Rigidbody>().freezeRotation = true;
    }
    // Update is called once per frame
    void LateUpdate () {

        if (EventSystem.current.IsPointerOverGameObject()||_target ==null)
        {
            return;
        }

        if (Application.platform == RuntimePlatform.IPhonePlayer)
        {
            if (Input.touchCount == 1)
            {
                if (Input.GetTouch(0).phase == TouchPhase.Moved)
                {
                    orbit = true;
                }
                else
                {
                    orbit = false;
                }
            }
            else
            {
                orbit = false;
            }

            if (Input.touchCount > 1)
            {
                if (Input.GetTouch(0).phase == TouchPhase.Moved || Input.GetTouch(1).phase == TouchPhase.Moved)
                {
                    var tempPosition1 = Input.GetTouch(0).position;
                    var tempPosition2 = Input.GetTouch(1).position;
                    if (isEnlarge(oldPosition1, oldPosition2, tempPosition1, tempPosition2))
                    {
                        zoomValue = 0.1f;
                        zoom = true;
                    }
                    else
                    {
                        zoomValue = -0.1f;
                        zoom = true;
                    }
                    oldPosition1 = tempPosition1;
                    oldPosition2 = tempPosition2;
                }
                else
                {
                    zoom = false;
                }
            }
            else
            {
                zoom = false;
            }
        } 
       else if (Application.platform == RuntimePlatform.Android)
        {

            if (Input.touchCount == 1)
            {
                if (Input.GetTouch(0).phase == TouchPhase.Moved)
                {
                    orbit = true;
                }
                else
                {
                    orbit = false;
                }
            }
            else
            {
                orbit = false;
            }

            if (Input.touchCount > 1)
            {
                if (Input.GetTouch(0).phase == TouchPhase.Moved || Input.GetTouch(1).phase == TouchPhase.Moved)
                {
                    var tempPosition1 = Input.GetTouch(0).position;
                    var tempPosition2 = Input.GetTouch(1).position;
                    if (isEnlarge(oldPosition1, oldPosition2, tempPosition1, tempPosition2))
                    {
                        zoomValue = 0.1f;
                        zoom = true;
                    }
                    else
                    {
                        zoomValue = -0.1f;
                        zoom = true;
                    }
                    oldPosition1 = tempPosition1;
                    oldPosition2 = tempPosition2;
                }
                else
                {
                    zoom = false;
                }
            }
            else
            {
                zoom = false;
            }
        }
        else
        {
            if (Input.GetMouseButton(1))
            {
                orbit = true;
            }
            else
            {
                orbit = false;
            }

            if (Input.GetAxisRaw("Mouse ScrollWheel") != null)
            {
                zoomValue = Input.GetAxisRaw("Mouse ScrollWheel");
                zoom = true;
            }
            else
            {
                zoom = false;
            }
        }

        if (orbit)
        {

            orbitDampX = Mathf.Lerp(orbitDampX, Input.GetAxis("Mouse X"), dampingTime * Time.deltaTime);
            orbitDampY = Mathf.Lerp(orbitDampY, Input.GetAxis("Mouse Y"), dampingTime * Time.deltaTime);
        }
        else
        {
            orbitDampX = Mathf.Lerp(orbitDampX, 0, dampingTime * Time.deltaTime);
            orbitDampY = Mathf.Lerp(orbitDampY, 0, dampingTime * Time.deltaTime);
        }

        if (zoom)
        {
            zoomDamp = Mathf.Lerp(zoomDamp, zoomValue, dampingTime * Time.deltaTime);
        }
        else
        {
            zoomDamp = Mathf.Lerp(zoomDamp, 0, dampingTime * Time.deltaTime);
        }

        if (!checkLerp(orbitDampX, 0) || !checkLerp(orbitDampY, 0))
        {
            doOrbit();
        }
        if (!checkLerp(zoomDamp, 0))
        {
            doZoom();
        }

    }

    bool isEnlarge(Vector2 oP1,Vector2 oP2 , Vector2 nP1, Vector2 nP2 )  
    {   
        var leng1 =Mathf.Sqrt((oP1.x-oP2.x)*(oP1.x-oP2.x)+(oP1.y-oP2.y)*(oP1.y-oP2.y));   
        var leng2 =Mathf.Sqrt((nP1.x-nP2.x)*(nP1.x-nP2.x)+(nP1.y-nP2.y)*(nP1.y-nP2.y));   
        if(leng1<leng2)   
        {   
            //big
             return true;    
        }else   
        {   
            //small
            return false;    
        }   
    }

    bool checkLerp(float a,float b)
    {
        if (Mathf.Approximately(a, b))
        {
            return true;
        }
        return false;
    }
    void doOrbit()
    {
        if (_target) 
         {          
             x += orbitDampX * xSpeed * 0.02f;
             y -= orbitDampY * ySpeed * 0.02f;

            y = ClampAngle(y, yMinLimit, yMaxLimit);
            updateCamera();
        }
    }
    void doZoom()
    {
        distance -= zoomDamp * zoomFactor;
        distance = Mathf.Clamp(distance, -distLimit.x, distLimit.y);
        updateCamera();
    }

    void updateCamera()
    {
        var rotation = Quaternion.Euler(y, x, 0);
        var position = rotation * new Vector3(0.0f, 0.0f, -distance) + _target.position;

        transform.rotation = rotation;
        transform.position = position;
    }

    static float ClampAngle (float angle,float min,float max)
    {
        if (angle < -360)
            angle += 360;
        if (angle > 360)
            angle -= 360;
        return Mathf.Clamp(angle, min, max);
    }
}

vue-cli3构建的vue项目使用babel-polyfill兼容安卓低版本浏览器

vue-cli2构建的项目有很多教程写babel-polyfill,而最近我用了一个新的vue-cli3构建的项目,在兼容低版本安卓浏览器时遇到的问题,做一下记录。

一、babel-polyfill
IE 11版本浏览器不支持ES6百分之85%的语法规范,在vue项目中选择使用babel-polyfill兼容语法。

(1)安装babel-polyfill

npm install babel-polyfill --save-dev

(2)main.js

import 'babel/polyfill'

或者

import '@babel/polyfill'

这里尽可能在首行引入;注意一下node_module中polyfill的文件路径,有的可能是 import '@babel/polyfill' 这种情况。

(3)babel.config.js
配置内容如下:

module.exports = {
  presets: [
    ['@vue/app', {
      useBuiltIns: 'entry'
    }]
  ]
}

(4)vue.config.js
链式webpack配置函数,配置内容如下:

// module.exports内添加
chainWebpack (config) {
  config.entry('main').add('babel-polyfill')
}

vue项目实战:封装websocket请求(转载)

项目中需要用到websocket,网上找到一个简单又感觉还不错的封装,怕丢失了,特转载如下:
本文转载链接:https://blog.csdn.net/m0_38134431/article/details/105794108

前言:
如果项目中多个组件都使用到WebSocket请求,那么我们需要对WebSocket进行封装,方便我们使用。
下面我根据我的项目结构来创建文件和引入文件,大家注意一下自己项目结构。

一、在utils目录下创建websocket.js文件

import { Message } from 'element-ui'
import { getToken } from '@/utils/authToken' // 与后端的协商,websocket请求需要带上token参数
let websock = null
let messageCallback = null
let errorCallback = null
let wsUrl = ''

// 接收ws后端返回的数据
function websocketonmessage (e) { 
  messageCallback(JSON.parse(e.data))
}

/**
 * 发起websocket连接
 * @param {Object} agentData 需要向后台传递的参数数据
 */
function websocketSend (agentData) {
  // 加延迟是为了尽量让ws连接状态变为OPEN   
  setTimeout(() => { 
    // 添加状态判断,当为OPEN时,发送消息
    if (websock.readyState === websock.OPEN) { // websock.OPEN = 1 
      // 发给后端的数据需要字符串化
      websock.send(JSON.stringify(agentData))
    }
    if (websock.readyState === websock.CLOSED) { // websock.CLOSED = 3 
      console.log('websock.readyState=3')
      Message.error('ws连接异常,请稍候重试')
      errorCallback()
    }
  }, 500)
}

// 关闭ws连接
function websocketclose (e) {  
  // e.code === 1000  表示正常关闭。 无论为何目的而创建, 该链接都已成功完成任务。
  // e.code !== 1000  表示非正常关闭。
  if (e && e.code !== 1000) {
    Message.error('ws连接异常,请稍候重试')
    errorCallback()
  }
}
// 建立ws连接
function websocketOpen (e) {
  // console.log('ws连接成功')
}

// 初始化weosocket
function initWebSocket () { 
  if (typeof (WebSocket) === 'undefined') {
    Message.error('您的浏览器不支持WebSocket,无法获取数据')
    return false
  }

  const token = 'JWT=' + getToken()
  // ws请求完整地址
  const requstWsUrl = wsUrl + '?' + token
  websock = new WebSocket(requstWsUrl)

  websock.onmessage = function (e) {
    websocketonmessage(e)
  } 
  websock.onopen = function () {
    websocketOpen()
  }
  websock.onerror = function () {
    Message.error('ws连接异常,请稍候重试')
    errorCallback()
  }
  websock.onclose = function (e) {
    websocketclose(e)
  } 
}

/**
 * 发起websocket请求函数
 * @param {string} url ws连接地址
 * @param {Object} agentData 传给后台的参数
 * @param {function} successCallback 接收到ws数据,对数据进行处理的回调函数
 * @param {function} errCallback ws连接错误的回调函数
 */
export function sendWebsocket (url, agentData, successCallback, errCallback) { 
  wsUrl = url
  initWebSocket()
  messageCallback = successCallback
  errorCallback = errCallback
  websocketSend(agentData)
}

/**
 * 关闭websocket函数
 */
export function closeWebsocket () {
  if (websock) {
    websock.close() // 关闭websocket
    websock.onclose() // 关闭websocket
  }
}

二、在vue组件中使用WebSocket封装好的功能

<template>
  <div>
    <button @click="requstWs">点击发起websocket请求</button>
  </div>
</template>
<script>
import { sendWebsocket, closeWebsocket } from '@/utils/websocket.js'

export default {
  beforeDestroy () {
    // 页面销毁时关闭ws。因为有可能ws连接接收数据尚未完成,用户就跳转了页面
    // 在需要主动关闭ws的地方都可以调用该方法
    closeWebsocket()
  },
  methods: {
    // ws连接成功,后台返回的ws数据,组件要拿数据渲染页面等操作
    wsMessage (data) {
      const dataJson = data
      console.log(dataJson)
      // 这里写拿到数据后的业务代码
    },
    // ws连接失败,组件要执行的代码
    wsError () {
      // 比如取消页面的loading
    },
    requstWs () {
      // 防止用户多次连续点击发起请求,所以要先关闭上次的ws请求。
      closeWebsocket()
      // 跟后端协商,需要什么参数数据给后台
      const obj = {
        monitorUrl: 'xxxxxxxxxxxxx',
        userName: 'xxxxxxxxxx'
      }
      // 发起ws请求
      sendWebsocket('ws://test.ws.com', obj, this.wsMessage, this.wsError)
    }
  }
}
</script>

介绍WebSocket对象中的readyState属性
WebSocket的readyState属性用来定义连接状态,该属性的值有下面几种:

0 :对应常量 CONNECTING
正在建立连接连接,还没有完成。
1 :对应常量 OPEN
连接成功建立,可以进行通信。
2 :对应常量 CLOSING
连接正在进行关闭握手,即将关闭。
3 : 对应常量 CLOSED
连接已经关闭或者根本没有建立。

介绍WebSocket断开连接onclose的重要信息错误状态码
WebSocket断开时,会触发CloseEvent, CloseEvent会在连接关闭时发送给使用 WebSockets 的客户端. 它在 WebSocket 对象的 onclose 事件监听器中使用。CloseEvent的code字段表示了WebSocket断开的原因。可以从该字段中分析断开的原因。

CloseEvent有三个字段需要注意, 通过分析这三个字段,一般就可以找到断开原因。

CloseEvent.code: code是错误码,是整数类型
CloseEvent.reason: reason是断开原因,是字符串
CloseEvent.wasClean: wasClean表示是否正常断开,是布尔值。一般正常断开时,该值为true

如下是在关闭ws连接的时候打印出来的CloseEvent对象:

关闭状态码表
下面标红的状态码是我在项目中测试遇到过的。

状态码 描述
0–999 保留段, 未使用
1000 正常关闭; 无论为何目的而创建, 该链接都已成功完成任务.
1001 终端离开, 可能因为服务端错误, 也可能因为浏览器正从打开连接的页面跳转离开.
1002 由于协议错误而中断连接.
1003 由于接收到不允许的数据类型而断开连接 (如仅接收文本数据的终端接收到了二进制数据).
1004 保留. 其意义可能会在未来定义.
1005 保留. 表示没有收到预期的状态码.
1006 保留. 用于期望收到状态码时连接非正常关闭 (也就是说, 没有发送关闭帧).
1007 由于收到了格式不符的数据而断开连接 (如文本消息中包含了非 UTF-8 数据).
1008 由于收到不符合约定的数据而断开连接. 这是一个通用状态码, 用于不适合使用 1003 和 1009 状态码的场景.
1009 由于收到过大的数据帧而断开连接.
1010 客户端期望服务器商定一个或多个拓展, 但服务器没有处理, 因此客户端断开连接.
1011 客户端由于遇到没有预料的情况阻止其完成请求, 因此服务端断开连接.
1012 服务器由于重启而断开连接.
1013 服务器由于临时原因断开连接, 如服务器过载因此断开一部分客户端连接.
1014 由 WebSocket标准保留以便未来使用.
1015 保留. 表示连接由于无法完成 TLS 握手而关闭 (例如无法验证服务器证书).
1016–1999 由 WebSocket标准保留以便未来使用.
2000–2999 由 WebSocket拓展保留使用.
ps: 其他注意事项
如果你的服务所用的协议是HTTPS的,那么使用的WebSocket协议也必须是wss, 而不能是ws

参考资料链接:
https://www.cnblogs.com/scott-j/p/9306197.html
https://segmentfault.com/a/1190000014582485?utm_source=tag-newest
https://blog.csdn.net/qq_39186346/article/details/81941664

Mac电脑通过nvm来管理node版本

碰到node的依赖包加载问题,尝试升级node版本解决,
升级系统node的时候,老是忘记自己用的node版本管理器,做个记录。

zhujin@MacBook-Pro ~ % nvm list
       v0.10.32
         v6.1.0
        v7.10.0
         v8.7.0
        v8.10.0
         v9.4.0
        v12.4.0
->      v13.0.1
         system
default -> 13.0.1 (-> v13.0.1)
node -> stable (-> v13.0.1) (default)
stable -> 13.0 (-> v13.0.1) (default)
unstable -> N/A (default)
iojs -> iojs- (-> system) (default)
lts/* -> lts/erbium (-> N/A)
lts/argon -> v4.9.1 (-> N/A)
lts/boron -> v6.17.1 (-> N/A)
lts/carbon -> v8.17.0 (-> N/A)
lts/dubnium -> v10.22.0 (-> N/A)
lts/erbium -> v12.18.3 (-> N/A)

升级命令 nvm install stable

zhujin@MacBook-Pro ~ % nvm install stable
Downloading and installing node v14.7.0...
Downloading https://nodejs.org/dist/v14.7.0/node-v14.7.0-darwin-x64.tar.xz...
################################################################################################################# 100.0%
Computing checksum with shasum -a 256
Checksums matched!
Now using node v14.7.0 (npm v6.14.7)

然后当前的终端已经版本OK了,然后你会发现每次打开终端,都会自动把版本变回去,所以最后需要设置默认node版本:

nvm alias default 14.7.0

3dmax 用了2个材质贴图,发生了贴图错位、透视和重叠

3dmax 用了2个材质贴图,发生了透视和重叠,2个贴图一个是不透明的,一个是透明的,只要透明的加上,就部分透视了。
一开始以为是法线或者是图片通道的问题,改啊弄啊怎么都不能顺利解决。
接近花了一整天之后,终于发现了解决方法,shift+f3就解决了,原因未知,特此记录。

关于 “SetDestination can only be called on an active agent that has been placed on a NavMesh” 真正的解决方案

最近碰到了 "SetDestination can only be called on an active agent that has been placed on a NavMesh" 的问题,关键点不在于不会用Navmesh,而是真的他就这么报错了。

找了很多办法,耗时1天,终于在国外论坛上看到真正的解决方案了。

常规解决方案:

  1. 检查场景是否烘焙。
  2. 检查目标或自己是否位于navmesh上,不是在半空。
  3. 尝试使用NavMesh.SamplePosition方法。
    GameObject go = new GameObject("Target");
    Vector3 sourcePostion = new Vector3( 100, 20, 100 );//The position you want to place your agent
    NavMeshHit closestHit;
    if( NavMesh.SamplePosition(  sourcePostion, out closestHit, 500, 1 ) ){
      go.transform.position = closestHit.position;
      go.AddComponent<NavMeshAgent>();
      //TODO
    }
    else{
      Debug.Log("...");
    }

如果常规方法没解决,且寻路是时好时坏,对象和自己均是代码生成的,那八九不离十肯定碰到了我碰到的问题。
解决方法很简单:
在prefab里就添加了NavMeshAgent组件的,把他勾掉,然后在物体的start里面agent.enabled = true;
如果是在awake代码生成的,AddComponent后把enabled设置成false,然后在物体的start里面agent.enabled = true;

示例:

void Awake () {
    // 添加寻路组件
    agent = this.gameObject.AddComponent<NavMeshAgent> ();
    agent.speed = 3.5f;
    agent.enabled = false;
    // ...
}

// Use this for initialization
void Start () {
    agent.enabled = true;
}