实现点击穿透判定 | 实现像素级别点击触摸判定 | 实现透明像素不算点击

需求:实现点击穿透判定 | 实现像素级别点击触摸判定 | 实现透明像素不算点击

参考

cocos creator实现触摸特效,触摸穿透
creator2.x 获取图片的像素数据
点击获取图片像素-示例
RenderUtil (注意!放大后不准确)

解决方案

以下是我借鉴整合并解决了放大问题

const {ccclass, property} = cc._decorator;

@ccclass
export default class touch2 extends cc.Component {
    protected onLoad(): void {
        this.InitTouch();
    }

    private _eventManager = cc["internal"]["eventManager"];
    private _touchListener: any;

    InitTouch() {
        const EventListener = cc["EventListener"];
        this._touchListener = EventListener.create({
            event: EventListener.TOUCH_ONE_BY_ONE,
            swallowTouches: false,//是否吞噬touch事件
            owner: this.node,
            mask: null,
            onTouchBegan: this.onTouchStart.bind(this),
            onTouchMoved: null,
            onTouchEnded: this.onTouchEnded.bind(this),
            onTouchCancelled: null,
        });
        this._eventManager.addListener(this._touchListener, this.node);        
    }
    private static pool: Set<string> = new Set;

    private onTouchStart(touch: cc.Touch, event: cc.Event.EventTouch): boolean {
        // cc.log("touch start = " + this.node.name);
        //此处必须返回true(表示接触到了节点),否则TOUCH_MOVE,TOUCH_END,TOUCH_CANCEL不触发。
        if (this.IsTouchSuccess(touch)) {
            touch2.pool.add(this.node.name)
        }
        return true;
    }
    private onTouchEnded(touch: cc.Touch, event: cc.Event.EventTouch): void {
        // cc.log("touch end = " + this.node.name);
        if (!touch2.pool.has(this.node.name)) {
            return
        }
        touch2.pool.clear()
        this.onTargetClick();
    }
    protected onDestroy(): void {
        // super.onDestroy();
        this._eventManager.removeListener(this._touchListener, this.node);
    }
    protected pixelsData: Uint8Array = null;
    private IsTouchSuccess(touch: cc.Touch): boolean {
        // 点击位置
        const touchPos = touch.getLocation()
        const localPos = this.node.convertToNodeSpaceAR(touchPos);
        if (!this.node.getBoundingBoxToWorld().contains(touchPos)) {
            return false; // 不在节点内
        }
        // 获取像素数据
        if (!this.pixelsData) {
            this.pixelsData = this.getPixelsData(this.node);
            // 将收集到的像素数据存储到全局变量或其他需要共享的位置
            cc.game.emit("pixelsDataCollected", this.pixelsData);
        }
        // 截取像素颜色
        let x = localPos.x + this.node.anchorX * this.node.width,
            y = -(localPos.y - this.node.anchorY * this.node.height);
        // 图片放大的话,像素数据也相应变多
        let cellSize = this.node.scaleX * 4
        let index = (this.node.width * cellSize * (Math.floor(y) * this.node.scaleY)) + (cellSize * Math.floor(x))
        
        const colors = this.pixelsData.slice(index, index + cellSize);
        if (colors[3] == 0) {
            return false; // 点在透明像素上
        }
        return true;
    }
    private onTargetClick() {
        console.log(this.node.name);    
    }

    /**
     * 获取像素数据
     * @param node 节点
     * @param flipY 垂直翻转数据
     */
    public getPixelsData(node: cc.Node, flipY: boolean = true) {
        if (!cc.isValid(node)) {
            return null;
        }
        // 节点宽高
        const width = node.width * node.scaleX,
            height = node.height * node.scaleY;
            
        // 创建临时摄像机用于渲染目标节点
        const cameraNode = new cc.Node();
        cameraNode.parent = node;
        const camera = cameraNode.addComponent(cc.Camera);
        camera.clearFlags |= cc.Camera.ClearFlags.COLOR;
        camera.backgroundColor = cc.color(0, 0, 0, 0);
        camera.zoomRatio = cc.winSize.height / height;
        
        // 将节点渲染到 RenderTexture 中
        const renderTexture = new cc.RenderTexture();
        renderTexture.initWithSize(width, height, cc.RenderTexture.DepthStencilFormat.RB_FMT_S8);
        camera.targetTexture = renderTexture;
        camera.render(node);
        // 获取像素数据
        const pixelsData = renderTexture.readPixels();
        
        // 销毁临时对象并返回数据
        renderTexture.destroy();
        cameraNode.destroy();
        // 垂直翻转数据
        if (flipY) {
            const length = pixelsData.length,
                lineWidth = width * 4,
                data = new Uint8Array(length);
            for (let i = 0, j = length - lineWidth; i < length; i += lineWidth, j -= lineWidth) {
                for (let k = 0; k < lineWidth; k++) {
                    data[i + k] = pixelsData[j + k];
                }
            }
            return data;
        }
        return pixelsData;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Android中实现透明Activity的点击穿透,可以通过以下步骤进行操作: 1. 在Manifest文件中声明透明的Activity: ```xml <activity android:name=".TransparentActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar"> </activity> ``` 2. 创建TransparentActivity类并继承自Activity,并在onCreate方法中设置Activity的透明属性: ```java public class TransparentActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 设置Activity透明 getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); getWindow().setFlags(WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH); // 设置布局等其他操作 setContentView(R.layout.activity_transparent); } } ``` 3. 在TransparentActivity的布局文件中,可以添加其他View元素,以便显示其他内容。 ```xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="This is a transparent activity" android:textSize="24sp" android:layout_centerInParent="true"/> <!--其他View元素--> </RelativeLayout> ``` 通过以上步骤,我们可以创建一个透明的Activity,并且该Activity不会拦截点击事件,点击事件会传递到下方的View,从而实现透明Activity的点击穿透效果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值