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

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

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

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

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

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

这不,需求文档就来了:

改掉常见的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
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

李一恩

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

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

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

打赏作者

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

抵扣说明:

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

余额充值