Recently, a friend asked me how to deal with various shapes of the line of sight. How to achieve repeated horizontal jump line of sight? Recently, I happened to see a ray detection on the physics system in Cocos Creator Game Development Field, so BASED on this ray detection, I wrote a line of sight effect with repeated horizontal jump. Read on! Get the full project at the bottom of this article!
International practice, first on the final effect!
We need a little bit of vector knowledge before we talk about it, just a little bit!
Vector addition, OA plus AB is equal to OB
The dot product of a vector, the projection of one vector onto another vector, is a scalar, plus or minus. The Angle between vectors is positive if it is less than 90 degrees, zero if it is 90 degrees, and negative if it is greater than 90 degrees.
The cross product of a vector, resulting in a vector, is perpendicular to the plane of two vectors, also known as a normal vector. I’m not going to use it here, by the way.
Now let’s get to the point, where we have the incident vector, the normal vector, how do we get the reflection vector?
We shift the reflection vector to the beginning of the incident vector, extend the normal vector to intersect it, and the length of the extension line is exactly twice the negative of the projection of the incident vector onto the normal vector. The calculation formula of reflection vector can be derived from projection and vector addition.
Is that clear? It doesn’t matter if you are not clear, just remember the last formula, and then enter the operation of Cocos Creator.
Since this is collision detection in the physical system, we added the collider in the physical system in the editor, not the engine collider, do not choose the wrong one.
The stationary rigid body type is set to static, and after adding all physical colliders, it looks like this.
When you need a physics engine, you turn the physics engine on.
cc.director.getPhysicsManager().enabled = true;Copy the code
How is radiographic detection done? The results of radiographic detection are obtained by starting point, incident direction and length of remaining line segment. If the collision body is detected, the ray section is drawn, and the reflection direction is calculated, and the ray detection is carried out again. If no collider is detected, draw the remaining line segment. The main code is as follows:
/** * @description calculate ray * @param startLocation startLocation world coordinate * @param vector_dir unit direction vector */ private drawRayCast(startLocation: cc.Vec2, vector_dir: Cc.vec2) {// Remaining length const left_length = AIM_LINE_MAX_LENGTH - this._cur_length; if (left_length <= 0) return; Const endLocation = startLocation.add(vector_dir.mul(left_length)); // Const endLocation = startLocation.add(vector_dir.mul(left_length)); / / ray testing const results = cc. Director. GetPhysicsManager (). RayCast (startLocation endLocation, cc. RayCastType. Closest); if (results.length > 0) { const result = results[0]; // Specifies the point at which the ray intersects the passing collider. const point = result.point; This. drawAimLine(startLocation, point); Const line_length = point.sub(startLocation).mag(); This. _cur_length += line_length; // Specifies the normal unit vector of the collider's surface at the intersection point. const vector_n = result.normal; // Const vector_i = vector_dir; // Const vector_r = vector_i.sub(vector_n.mul(2 * vector_i.dot(vector_n))); // Const vector_r = vector_i.sub(vector_n. This. drawRayCast(point, vector_r); } else {this.drawAimLine(startLocation, endLocation); }}Copy the code
How to draw small circle of sight line? Calculate the number and spacing vectors by ending and starting positions, drawing small circles. The reference code is as follows.
/** * @description draw the sighting line * @param startLocation * @param endLocation */ private drawAimLine(startLocation: cc.Vec2, endLocation: Cc. Vec2) {/ / conversion coordinates const graphic_startLocation = this. Graphic_line. Node. ConvertToNodeSpaceAR (startLocation); this.graphic_line.moveTo(graphic_startLocation.x, graphic_startLocation.y); Const delta = 20; // Const vector_dir = endLocation.sub(startLocation); // Const total_count = math.round (vector_dir.mag()/delta); // Each interval vector vector_dir.normalizeself ().mulself (delta); for (let index = 0; index < total_count; index++) { graphic_startLocation.addSelf(vector_dir) this.graphic_line.circle(graphic_startLocation.x, graphic_startLocation.y, 2); }}Copy the code
The complete code