Industrial Control SCADA Simulation Aircraft Flight Based on HTML5 Canvas

I saw an article yesterday about learning how to fly an airplane, and I thought, if I could fly an airplane, it would be fun, everyone wants to be a pilot when they are kids! Chinese pilots are too difficult to be a pilot, and it is not easy to let you fly a plane! Later, I thought that it would be really interesting if I could use HT to fly a plane, haha, the effect of this realization is still very good, and it can satisfy your vanity of flying a plane.giggle

Demo site: http://hightopo.com/guide/guide/plugin/obj/examples/example_path.html

Let's take a look at the specific effect:

This example basically completely simulates the flight mode of the aircraft, including the take-off runway, including the movement path of the aircraft, the rotation of the propeller, the indicator lights at the tail and other parts.

First of all, the most important thing is our aircraft model. As mentioned in the previous article, HT encapsulates a method ht.Default.loadObj to load the OBJ file:

ht.Default.loadObj('obj/plane.obj', 'obj/plane.mtl', {                    
    center: true,
    r3: [0, -Math.PI/2, 0], // make plane face right
    s3: [0.15, 0.15, 0.15], // make plane smaller
    finishFunc: function(modelMap, array, rawS3){
        if(modelMap){                            
            modelMap.propeller.r3 = {//propeller propeller
            func: function(data){
                return [data.a('angle'), 0, 0];
            }
        };                             
        // make propeller a litter bigger
        modelMap.propeller.s3 = [1, 1.2, 1.2];
        modelMap.propeller.color = 'yellow';
    }
});

 

The modelMap.propeller here is the propeller object in the modelMap object defined in the OBJ file. You can try to print the modelMap to see the output.

The finishFunc(modelMap, array, rawS3) in this method is used for callback processing after loading. Please refer to the  HT for Web OBJ manual for details . We also added a "red flashing indicator light" at the tail of the aircraft that is not available in the OBJ model, here What is used is the combined model array (an array of all materials, with at least one model in it), we add a new ball model to the array:

// add a sphere model as an indicator light
array.push({
    shape3d: ht.Default.createSmoothSphereModel(),
    t3: [-40, 10, 0],
    s3: [6, 6, 6],
    color: {
        func: function(data){
            return data.a('light') ? 'red': 'black';
        }
    }
});

The shape3d here is an attribute name encapsulated by HT, which is registered by the setShape3dModel(name, model) function or the registered 3D model returned by the getShape3dModel(name) function. How to register the 3D model can be found in the  HT for Web Modeling Manual .

 

The color attribute name corresponds to an object. The definition here is as follows. Color directly obtains the value in data.setAttr('a', value) through data.getAttr('a'), which has two advantages. One It is a common attribute operation that can not pollute HT, so HT specially defines this attr attribute type, which is reserved by HT for users to store business data; second, this is also very convenient for data binding, we can change the attribute by changing the place. It is very convenient to call the setAttr method.

Then we register the model array we just combined as the "plane" model we want through ht.Default.setShape3dModel(name, model):

ht.Default.setShape3dModel('plane', array);

After registering the model, we must call this model. We can call this model through the shape3d attribute, and customize the light attribute and angle attribute that appeared in the above code in this model:

plane = new ht.Node();
plane.s3(200, 200, 200);
plane.s3(rawS3);
plane.s({
    'shape3d': 'plane',
    'shape3d.scaleable': false,
    'wf.visible': true,//Whether the wireframe is visible
    'wf.color': 'white',
    'wf.short': true //Whether to display closed wireframe, true is not closed short wireframe
});
plane.a({
    'angle': 0,
    'light': false
});

 

Because the aircraft also has two functions of propeller and indicator light, we have to animate these two models. You can refer to the  HT for Web animation manual , and determine the flight duration of the aircraft and watch the aircraft through the results selected by the user on the form form. The angle of view of the aircraft, the rotation angle of the aircraft to fly along the "route", the "flash" function of the tail indicator, etc. Finally, don't forget that when the aircraft stops flying, if you want the aircraft to continue flying, you have to call back this animation, and Set the lights to stop blinking and don't forget to start the animation:

params = {
    delay: 1500,
    duration: 20000,
    easing: function(t){
        return (t *= 2) < 1 ? 0.5 * t * t : 0.5 * (1 - (--t) * (t - 2));
    },
    action: function(v, t){
        var length = g3d.getLineLength(polyline),
        offset = g3d.getLineOffset(polyline, length*v),
        point = offset.point,
        px = point.x,
        py = point.y,
        pz = point.z,
        tangent = offset.tangent,
        tx = tangent.x,
        ty = tangent.y,
        tz = tangent.z;
        plane.p3(px, py, pz);
        plane.lookAt([px + tx, py + ty, pz + tz], 'right');
                        
        var camera = formPane.v ('Camera');
        if(camera === 'Look At'){
            g3d.setCenter(px, py, pz);
        }
        else if(camera === 'First Person'){                            
            g3d.setEye (px - tx * 400, py - ty * 400 + 30, pz - tz * 400);
            g3d.setCenter(px, py, pz);                            
        }
                        
        plane.a('angle', v*Math.PI*120);                        
        if(this.duration * t % 1000 > 500){
            plane.a('light', false);
        }else{
            plane.a('light', true);
        }                        
    },
    finishFunc: function(){
        animation = ht.Default.startAnim(params);
        plane.a('light', false);
    }                  
};                               
                
animation = ht.Default.startAnim(params);

In fact, what makes us most curious is that the depicted path has nothing to do with the flight of the aircraft itself. There are so many people who turn left and right. How can we do it?

Next, let's draw the path. First, the path is drawn based on ht.Polyline:

polyline = new ht.Polyline();   
polyline.setThickness(2);
polyline.s({
    'shape.border.pattern': [16, 16],
    'shape.border.color': 'red',
    'shape.border.gradient.color': 'yellow',
    'shape3d.resolution': 300,
    '3d.selectable': false
});
dataModel.add(polyline);

The above code just adds a polyline pipeline to the datamodel data model, and will not display anything. To display the "channel", we must first set the point where the channel is located. We first set the initial point of the channel:

points = [{ x: 0, y: 0, e: 0 }];
segments = [1];

The points and segments are  defined in the HT for Web Shape manual . Points is the fixed point information of the ht.List type array, and the vertex is an object in the format of { x: 100, y: 200 }; segments are the line segment array information of the ht.List type. , which represents how the vertices in the points array are connected in array order.

The multiple circular tracks on the left side of the "fairway" in the figure are also set by setting points and segments:

for(var k=0; k<count+1; k++){
    var angle = k * Math.PI * 2 * round / count;
    points.push({
        x: cx + radius * Math.cos(angle),
        y: cy + radius * Math.sin(angle),
        e: k * height / count
    });
    segments.push(2);
}

The next few inflection points are also implemented in this way, so I won’t go into details here. If you haven’t read the manual, here is a point. Segments can only take values ​​from 1 to 5. 1 represents the starting point of a new path; 2 represents the starting point of a new path. Connect to this point from the last last point; 3 occupy two point information, the first point is used as the curve control point, and the second point is used as the end point of the curve; 4 occupies 3 point information, the first and second points are used as the curve control point Curve control point, the third point is used as the end point of the curve; 5 does not occupy point information, which means the end of the current drawing path and is closed to the starting point of the path:

points.push({ x: cx+radius, y: 0, e: height/2 });
points.push({ x: 0, y: 0, e: height/2 });
segments.push(3);
     
points.push({ x: radius, y: -radius, e: height/2*0.7 });
points.push({ x: radius*2, y: radius, e: height/2*0.3 });
points.push({ x: radius*3, y: 0, e: 0 });
segments.push(4);   

points.push({ x: 0, y: 0, e: 0 });
segments.push(2);  

 

We have added the points on the path to the "channel", and then we need to set the points to the pipeline before they will be displayed on the interface:

polyline.setPoints(points);
polyline.setSegments(segments);  

 

"Runway" is relatively simple, just a Node node and then set the basic effect, nothing special:

runway = new ht.Node();
runway.s3(-cx+radius*3, 1, 200);
runway.p3(cx+runway.getWidth()/2, -22, 0);
runway.s({
    'all.color': '#FAFAFA',
    'all.transparent': true,
    'all.reverse.cull': true,
    'all.opacity': 0.8,
    '3d.selectable': false
});
dataModel.add(runway);

Finally, add a formPane form panel to the interface, which can be added directly to the body after it is defined, so that it will not have a display connection with graph3dView.

formPane can use the formPane.addRow method to dynamically add rows. This method can directly interact with dynamically changing data. For example, whether there is an animation in this example, we use the checkBox to record the selected or unselected state:

{
    checkBox: {
        label: 'Animation',
        selected: true,
        onValueChanged: function(){
            if(this.isSelected()){
                animation.resume();
            }else{
                animation.pause();
            }                               
        }
    }
}

You can also record dynamically changed values ​​by setting "id", and then formPane will get the current value by calling formPane.v(id).

 

 

So far, the explanation of the whole Demo ends here. If you still don’t understand, you can check our official website  HT for Web first. If you still don’t understand, you can privately message me, but I hope you can read it carefully, otherwise it will be a waste of our time. , thank you~

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326397350&siteId=291194637