0%

CocosCreator3.x发射瞄准线

小球瞄准线在2D小游戏开发中是常用的功能,找了好久发现网上都是CocosCreator2.x相关的教程,如白玉无冰老师的《反复横跳的瞄准线!…》《creator 反复横跳瞄准线的实现》From飞猪001,刚好第一份实习时有个3.x项目需要小球瞄准功能,但是当时由于3.x更新了系列2.x的API一直没弄懂做不出来,今天解决了就做个记录(这里要特别感谢键兴哥哥的指导)。

基本准备: 创建2D项目==>新建场景==>设置项目的设计宽高:宽540高960

  • 在Canvas画布下创建Sprite节点名称为touch_node和Graphics节点名为graphic_line
  • 新建脚本Test.ts挂到Canvas节点上,复制以下下代码(保存Canvas节点上找到Test组件挂上touch_node和graphic_line节点):
  • 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
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    import { _decorator, BoxCollider2D, Component, EPhysics2DDrawFlags, ERaycast2DType, ERigidBody2DType, Node, PhysicsSystem2D, RigidBody2D, UITransform, Vec2, Vec3, RigidBody, Graphics } from 'cc';
    const { ccclass, property } = _decorator;

    @ccclass('Test')
    export class Test extends Component {

    line_height = 2000
    @property(Graphics)
    graphic_line: Graphics = null

    @property(Node)
    private touch_node: Node = null;

    protected onLoad(): void {
    PhysicsSystem2D.instance.enable = true;
    PhysicsSystem2D.instance.debugDrawFlags = EPhysics2DDrawFlags.Aabb |
    EPhysics2DDrawFlags.Pair |
    EPhysics2DDrawFlags.CenterOfMass |
    EPhysics2DDrawFlags.Joint |
    EPhysics2DDrawFlags.Shape;

    this.initModule()
    }

    protected start(): void {
    this.touch_node.on(Node.EventType.TOUCH_START, (event) => {
    console.log('true')
    this.resetLine(event.getLocation())
    }, this)
    this.touch_node.on(Node.EventType.TOUCH_MOVE, (event) => {
    this.resetLine(event.getLocation())
    }, this)
    }

    update(deltaTime: number) {

    }

    /**
    * 刷新线
    * @param touch_point
    */
    resetLine(touch_point: Vec2) {
    this.graphic_line.clear();
    let temp = this.graphic_line.node.getComponent(UITransform).convertToWorldSpaceAR(Vec3.ZERO);
    let start_point = new Vec2(temp.x, temp.y)

    let sub_vec = new Vec2(Vec2.ZERO)
    Vec2.subtract(sub_vec, touch_point, start_point)
    // let sub_vec = touch_point.sub(start_point);

    let end_point = new Vec2(Vec2.ZERO)
    let a = new Vec2(Vec2.ZERO);
    Vec2.divide(a, sub_vec, new Vec2(Vec2.len(sub_vec), Vec2.len(sub_vec)))
    let b = new Vec2()
    Vec2.multiplyScalar(b, a, this.line_height)
    end_point = b.add(start_point)
    // let end_point = sub_vec.div(sub_vec.mag()).mul(this.line_height).add(start_point);
    this.physicalRayCast(start_point, end_point, this.line_height);

    this.graphic_line.stroke();
    }

    /**
    * 射线检查
    * @param p1
    * @param p2
    * @param line_mag
    */
    physicalRayCast(p1: Vec2, p2: Vec2, line_mag: number) {
    //射线检测
    var results = PhysicsSystem2D.instance.raycast(p1, p2,
    ERaycast2DType.Closest)[0];
    let sub_vec: Vec2 = new Vec2();
    if (results) {
    Vec2.subtract(sub_vec, results.point, p1)
    // sub_vec = results.point.sub(p1);
    //计算长度
    let draw_mag = Vec2.len(sub_vec);
    //得到入射向量单位
    Vec2.divide(sub_vec, sub_vec, new Vec2(draw_mag, draw_mag));
    if (line_mag - draw_mag > 0) {
    let temp = this.node.getComponent(UITransform).convertToNodeSpaceAR(new Vec3(p1.x, p1.y, 0))
    this.drawLine(new Vec2(temp.x, temp.y), sub_vec, draw_mag);
    //法向量
    p1 = results.point;
    //反射法向量
    let mul = new Vec2()
    Vec2.multiply(mul, results.normal, new Vec2(2 * sub_vec.dot(results.normal), 2 * sub_vec.dot(results.normal)))
    Vec2.subtract(p2, sub_vec, mul)


    // p2 = sub_vec.sub(results.normal.mul(2*sub_vec.dot(results.normal)));
    p2.multiply(new Vec2(line_mag - draw_mag, line_mag - draw_mag))
    // p2.mul(line_mag - draw_mag, p2);
    //反射点
    p2.add(p1)
    this.physicalRayCast(p1, p2, line_mag - draw_mag);
    } else {
    let temp = this.node.getComponent(UITransform).convertToNodeSpaceAR(new Vec3(p1.x, p1.y, 0))
    this.drawLine(new Vec2(temp.x, temp.y), sub_vec, line_mag);
    }
    } else {
    Vec2.subtract(sub_vec, p2, p1)
    // sub_vec = p2.sub(p1);
    let draw_mag = Vec2.len(sub_vec);
    Vec2.divide(sub_vec, sub_vec, new Vec2(draw_mag, draw_mag));
    // sub_vec.divSelf(sub_vec.mag());

    let temp = this.node.getComponent(UITransform).convertToNodeSpaceAR(new Vec3(p1.x, p1.y, 0))
    this.drawLine(new Vec2(temp.x, temp.y), sub_vec, line_mag);
    }
    }


    /**
    * 画线
    * @param start_point
    * @param sub_vec
    * @param line_mag
    */
    drawLine(start_point: Vec2, sub_vec: Vec2, line_mag: number) {
    let a = new Vec2()
    Vec2.multiplyScalar(a, sub_vec, 20)
    let end_point = new Vec2()
    Vec2.add(end_point, start_point, a)
    this.graphic_line.moveTo(start_point.x, start_point.y);
    this.graphic_line.lineTo(end_point.x, end_point.y);
    line_mag -= 30;
    if (line_mag > 0) {
    let t = new Vec2()
    Vec2.multiplyScalar(t, sub_vec, 10)
    this.drawLine(end_point.add(t), sub_vec, line_mag);
    }
    }



    initModule() {
    let width = this.node.getComponent(UITransform).width
    let height = this.node.getComponent(UITransform).height;

    let node = new Node();

    let body = node.addComponent(RigidBody2D);
    body.type = ERigidBody2DType.Static;


    this._addBound(node, 0, height / 2, width, 20);
    this._addBound(node, 0, -height / 2, width, 20);
    this._addBound(node, -width / 2, 0, 20, height);
    this._addBound(node, width / 2, 0, 20, height);

    node.parent = this.node;
    }

    _addBound(node, x, y, width, height) {
    let collider = node.addComponent(BoxCollider2D); //PhysicsBoxCollider
    collider.offset.x = x;
    collider.offset.y = y;
    collider.size.width = width;
    collider.size.height = height;
    }

    }


这样一条基本的反复横跳瞄准线就完成了,当触摸touch_node时瞄准线就会随着手指的移动而发生变化。在自己的项目中也可以对这条线进行系列美化。具体后面会放在后面的升级代码中。

-------------本文结束感谢您的阅读-------------