三分钟教会你微信炸一炸,满屏粑粑也太可爱了!

相信这个特效你和你的朋友(或对象)一定玩过
请添加图片描述
当你发送一个便便的表情,对方如果扔一个炸弹表情,就会立刻将这个便便炸开,实现满屏粑粑的“酷炫”画面。可谓是“臭味十足”,隔着屏幕都能感受到来自微信爸爸的满满恶意。

不清楚大家对这个互动设计怎么看,反正一恩当时是喜欢的不行,拉着朋友们就开始“炸”得不亦乐乎。

同样被虏获芳心的设计小哥哥在玩到尽兴后,突然灵感大发,连夜绘制出了设计稿,第二天就拉上产品和研发开始脑暴。

“微信炸💩打动我的一点是他满屏的设计,能够将用户强烈的情绪抒发出来;同时他能够与上一条表情进行捆绑,加强双方的互动性。”设计小哥哥声情并茂道。

“所以,让我们的表情也‘互动’起来吧!”

这不,需求文档就来了:

改掉常见的emoji表情发送方式,替换为动态表情交互方式。即,
当用户发送或接收互动表情,表情会在屏幕上随机分布,展示一段时间后会消失。
用户可以频繁点击并不停发送表情,因此屏幕上的表情是可以非常多且重叠的,能够将用户感情强烈抒发。
请添加图片描述
(暂用微信的聊天界面进行解释说明,图1为原样式,图2是需求样式)

这需求一出,动态表情在屏幕上的分布方案便引起了研发内部热烈讨论:当用户点击表情时,到底应该将表情放置在屏幕哪个位置比较好呢?

最直接的做法就是完全随机方式:取0到屏幕宽度和高度中随机值,放置表情贴纸。但这么做的不确定因素太多,比如存在一定几率所有表情都集中在一个区域,布局边缘化以及最差的重叠问题。因此简单的随机算法对于用户的体验是无法接受的。

在这里插入图片描述

我们开始探索新的方案:
因为目前点的选择依赖于较多元素,比如与屏幕已有点的间距,与中心点距离以及屏幕已有点的数目。因此最终决定采用点权随机的方案,根据上述元素决策出屏幕上可用点的优度,选取优度最高的插入表情。

基本思路

维护对应屏幕像素的二维数组,数组元素代指新增图形时,图形中心取该点的优度。
采用懒加载的方式,即每次每次新增图形后,仅记录现有方块的位置,当需要一个点的优度时再计算。

遍历所有方块的位置,将图形内部的点优度全部减去 A ,将图形外部的点按到图形的曼哈顿距离从 0 到 max (W,H),映射,减 0 到 A * K2。
每次决策插入位置时,随机取 K + n * K1 个点,取这些点中优度最高的点为插入中心
A, K, K1, K2 四个常数可调整

一次选择的复杂度是 n * randT,n 是场上方块数, randT 是本次决策需要随机取多少个点。 从效率和 badcase来说,这个方案目前最优。

在这里插入图片描述

代码展示


```cpp
#include <iostream>
#include <vector>
using namespace std;
 
const int screenW = 600;
const int screenH = 800;
 
const int kInnerCost = 1e5;
const double kOuterCof = .1;
 
const int kOutterCost = kInnerCost * kOuterCof;
 
class square
    int x1;
    int x2;
    int y1;
    int y2;
};
 
int lineDist(int x, int y, int p){
    if (p < x) {
        return x - p;
    } else if (p > y) {
        return p - y;
    } else {
        return 0;
    }
}
 
int getVal(const square &elm, int px, int py){
    int dx = lineDist(elm.x1, elm.x2, px);
    int dy = lineDist(elm.y1, elm.y2, py);
    int dist = dx + dy;
    constexpr int maxDist = screenW + screenH;
    return dist ? ( (maxDist - dist) * kOutterCost / maxDist ) : kInnerCost;
}
 
int getVal(const vector<square> &elmArr, int px, int py){
    int rtn = 0;
    for (auto elm:elmArr) {
        rtn += getVal(elm, px, py);
    }
    return rtn;
}
 
int main(void){
    
    int n;
    cin >> n;
 
    vector<square> elmArr;
    for (int i=0; i<n; i++) {
        square cur;
        cin >> cur.x1 >> cur.x2 >> cur.y1 >> cur.y2;
        elmArr.push_back(cur);
    }
 
 
    for (;;) {
        int px,py;
        cin >> px >> py;
        cout << getVal(elmArr, px, py) << endl;
    }
 
}

优化点

  1. 该算法最优解偏向边缘。因此随着随机值设置越多,得出来的点越偏向边缘,因此随机值不能设置过多。
  2. 为了解决偏向边缘的问题,每一个点在计算优度getVal需要加上与屏幕中心的距离 * n * k3

效果演示

最后就是给大家演示一下最后的效果啦!
请添加图片描述
圆满完成任务,收工,下班!

  • 13
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
OpenWrt是一个基于Linux的嵌入式操作系统,用于路由器和其他嵌入式设备。它提供了丰富的功能和自定义选项,但对于一些用户来说,在配置和安装上可能稍显复杂。以下是一个简化的OpenWrt安装教程,只需要三分钟和三个简单的步骤即可完成。 第一步,准备工作。首先,确保你拥有兼容OpenWrt固件的路由器设备,并且已连接好电源和网络线。其次,访问OpenWrt官方网站,下载适用于你的路由器型号和版本的固件文件。将该文件保存到你的计算机上。 第二步,进入路由器管理界面。打开你的浏览器,并在地址栏中输入“192.168.1.1”这个默认的路由器管理IP地址。如果你的路由器IP地址有所不同,请查阅相关的资料。在登录界面输入默认的用户名和密码,通常为“root”和“admin”。登录成功后,你将进入路由器的管理页面。 第三步,安装OpenWrt固件。在路由器管理页面中,找到“系统设置”或“固件升级”等类似选项。点击“浏览”按钮,选择之前下载好的OpenWrt固件文件,并点击“安装”或“升级”按钮。等待数分钟,直到固件文件安装完成并路由器自动重启。 通过以上三个简单的步骤,你就可以完成OpenWrt的安装了。安装完成后,你可以进一步在管理界面中自定义设置、添加插件和配置网络等。请注意,在进行任何操作前,务必备份你的路由器配置和数据,以免造成不可挽回的损失。有需要时,也可以参考官方文档和社区论坛,深入了解和利用OpenWrt的更多功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李一恩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值