异步操作Promise

前言

写了一个脚本,又回想起了之前的前端知识。

https://github.com/ancientElement/bilibili-filter-home

过滤指定类型的哔哩哔哩首页视频。喜欢的话可以点个星星。

关于Promise

一开始学的时候其实是看不懂的,之前做前端也是懵懵懂懂。
Promise就是将回调进行了封装,另外可以使用await等待reject或者reslove的执行;
明白了原理之后其实很好复现。

复现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class Test
{
public Test()
{
Promise<int, int> promise = new Promise<int, int>((reslove, reject) =>
{
reslove(10);
});
promise.Then((res) =>
{
Debug.Log(res);
});
}
}

public class Promise<TRes, TError>
{
public delegate void funReslove(TRes res);
public delegate void funReject(TError err);
public delegate void fun(funReslove reslove, funReject reject);
public funReslove m_reslove;
public funReject m_reject;
public fun m_fun;

public Promise(fun fun)
{
m_fun = fun;
m_fun?.Invoke(m_reslove, m_reject);
}
public void Then(funReslove reslove)
{
m_reslove += reslove;
}
public void Catch(funReject reject)
{
m_reject += reject;
}
}

命令模式

这个命令模式确实有点意思,可以将判断与执行解耦,并且可以回退,原因是Commmad记录了操作对象执行命令之前的状态,或者Revock可以给到一个相反的状态

并且文中提到如果使用第一公民函数的语言和闭包也可以实现,重点就是要可以记录状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
public interface BaseCommand
{
/// <summary>
/// 执行命令
/// </summary>
/// <param name="command"></param>
/// <param name="obj"></param>
public void Execute(GameObject gameObject);
/// <summary>
/// 回退命令
/// </summary>
/// <param name="obj"></param>
public void Revoke(GameObject gameObject);
}

public class MoveCommand : BaseCommand
{
private GameObject m_gameObject;
private Vector3 m_direction;

public MoveCommand(Vector3 dir)
{
m_direction = dir;
}

public void Execute(GameObject obj)
{
m_gameObject = obj;
m_gameObject.transform.Translate(m_direction);
}

public void Revoke(GameObject obj)
{
m_gameObject = obj;
m_gameObject.transform.Translate(Quaternion.Euler(0f, 180f, 0f) * m_direction);
}
}

public static class CommandManager
{
private static Stack<BaseCommand> m_commands = new Stack<BaseCommand>();
public static void Clear() { m_commands.Clear(); }
/// <summary>
/// 执行命令
/// </summary>
/// <param name="command"></param>
/// <param name="obj"></param>
public static void Excute(BaseCommand command, GameObject obj)
{
command.Execute(obj);
m_commands.Push(command);
}
/// <summary>
/// 回退命令
/// </summary>
/// <param name="obj"></param>
public static void Revock(GameObject obj)
{
if (m_commands.TryPop(out BaseCommand commmand))
{
commmand.Revoke(obj);
}
}
}

public class TestCommandMode : MonoBehaviour
{
private MoveCommand m_moveForwad;
private MoveCommand m_moveBack;
private MoveCommand m_moveLeft;
private MoveCommand m_moveRight;

private void Start()
{
m_moveForwad = new MoveCommand(Vector3.forward);
m_moveBack = new MoveCommand(Vector3.back);
m_moveLeft = new MoveCommand(Vector3.left);
m_moveRight = new MoveCommand(Vector3.right);
}

private void Update()
{
if (Input.GetKeyDown(KeyCode.W))
{
CommandManager.Excute(m_moveForwad, gameObject);
}
if (Input.GetKeyDown(KeyCode.S))
{
CommandManager.Excute(m_moveBack, gameObject);
}
if (Input.GetKeyDown(KeyCode.A))
{
CommandManager.Excute(m_moveLeft, gameObject);
}
if (Input.GetKeyDown(KeyCode.D))
{
CommandManager.Excute(m_moveRight, gameObject);
}
if (Input.GetKeyDown(KeyCode.R))
{
CommandManager.Revock(gameObject);
}
}
}

帧同步流程与概述

逻辑与单机没有区别,只是输入分别来自服务器本地

帧同步如何同步?

  • 帧同步与单机类似,服务器转发所有玩家的输入,客户端根据接收到的输入推进游戏过程
  • 同样的代码,同样的输入 –> 同样的结果
  • 我们的服务器,每隔一端时间,将采集的玩家的操作,发给所有的客户端,继续采集下一次的操作,等一下一次时间到,又把采集到的操作发送给所有客户端;

Read More

分离轴算法

Reference

翻译自:Separating Axis Theorem (SAT) Explanation – sevenson.com.au

Separating Axis Theorem (SAT) Explanation

Separating Axis Theorem (SAT) is a technique for calculating collisions between convex polygons.
分离轴定理 (SAT) 是一种计算凸多边形之间碰撞的技术。

I’m by no means an expert on it, but after the need arose for me to do some collision detection I did a pile of reading and finally got it working in ActionScript 3.
我绝不是这方面的专家,但是在我需要做一些碰撞检测之后,我做了大量的阅读,最终让它在 ActionScript 3 中工作。

I thought I would share what I learned in the hope others wouldn’t suffer so much 🙂
我想我会分享我所学到的东西,希望其他人不会遭受那么多🙂痛苦

When I found myself in a need to calculate collisions between polygons in flash, I came across a method known as Separating Axis Theorem (SAT). The only problem I had was that I really struggled to get a grasp on it.
当我发现自己需要在 Flash 中计算多边形之间的碰撞时,我遇到了一种称为分离轴定理 (SAT) 的方法。我唯一的问题是我真的很难掌握它。

Read More

关于闭包

通俗易懂的讲,在C#中,闭包使用类实现,闭包函数变成了一个类,闭包中使用的变量(其定义域外的)变成了其成员变量,修改这个变量就是修改其成员变量,这样也就可以理解为什么修改闭包定义域以外的变量运行结果也会变化。

所以可以将闭包称为有状态的函数。

https://www.bilibili.com/video/BV1sY4y1U7BT

下面是js中的典型闭包:

1
2
3
4
5
for(var i=0;i<10;i++) {
setTimeout(()=>{
console.log(i)
},1000)
}

Read More

浅谈序列化

二进制

其实序列化有很多方法二进制序列化只是其中的一种,就是将类中的变量二进制的形式存储成为一个可读写的文件。

究其本源就是将类中的成员变量序列化成二进制数据,许多变量都可以进行二进制序列化,比如int``float``bool等等,就是将int转化成为16进制int,就是将float转化成为16进制flaot,就是将bool转化成为16进制bool

如果有的类不可以序列化,那么可能是没有实现自己的序列化方法。

这里就不讲解如何序列化一个类了,简单的来说就是实现一个Serilized方法,这个方法里面实现了每个值类型如何转化成为16进制数据,在这个方法里面,可以通过反射得到一个类所有的成员变量。然后将其成员变量按顺序转化为16进制数据,并且存储为二进制文件。

Read More