File size: 8,764 Bytes
09a6f7f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
const MAIN_BODY_POLYGONS = [
    [[-10, +10], [+10, +10], [+10, -10], [-10, -10]]
]
const MAIN_BODY_BOTTOM_WIDTH = 20
const SPIDER_SPEED_HIP = 4
const SPIDER_SPEED_KNEE = 6

/**
 * @classdesc Spider morphology.
 */
class SpiderBody extends WalkerAbstractBody {

    constructor(scale, motors_torque=100, nb_pairs_of_legs=2,
                nb_steps_under_water=600, reset_on_hull_critical_contact=false){
        super(scale, motors_torque, nb_steps_under_water);

        this.LEG_DOWN = 4 / this.SCALE;
        this.LEG_W = 6 / this.SCALE;
        this.LEG_H = 20 / this.SCALE;
        this.reset_on_critical_contact = reset_on_hull_critical_contact;

        this.nb_pairs_of_legs = nb_pairs_of_legs;

        this.TORQUE_PENALTY = 0.00035 / this.nb_pairs_of_legs;

        // not exacts but works
        this.AGENT_WIDTH = MAIN_BODY_BOTTOM_WIDTH / this.SCALE + this.LEG_H * 4;
        this.AGENT_HEIGHT = 20 / this.SCALE + this.LEG_H * 2;
        this.AGENT_CENTER_HEIGHT = this.LEG_H + this.LEG_DOWN;
    }

    draw(world, init_x, init_y, force_to_center){

        let fd_polygon;
        let vertices;

        /* Creates the different fixtures */

        let MAIN_BODY_FIXTURES = [];
        for(let polygon of MAIN_BODY_POLYGONS){
            fd_polygon = new b2.FixtureDef();
            fd_polygon.shape = new b2.PolygonShape();
            vertices = [];
            for(let vertex of polygon){
                vertices.push(new b2.Vec2(vertex[0] / this.SCALE, vertex[1] / this.SCALE));
            }
            fd_polygon.shape.Set(vertices, polygon.length);
            fd_polygon.density = 5.0;
            fd_polygon.friction = 0.1;
            fd_polygon.filter.categoryBits = 0x20;
            fd_polygon.filter.maskBits = 0x000F;
            MAIN_BODY_FIXTURES.push(fd_polygon);
        }

        let LEG_FD = new b2.FixtureDef();
        LEG_FD.shape = new b2.PolygonShape();
        LEG_FD.shape.SetAsBox(this.LEG_W / 2, this.LEG_H / 2);
        LEG_FD.density = 1.0;
        LEG_FD.restitution = 0.0;
        LEG_FD.filter.categoryBits = 0x20;
        LEG_FD.filter.maskBits = 0x000F;

        let LOWER_FD = new b2.FixtureDef();
        LOWER_FD.shape = new b2.PolygonShape();
        LOWER_FD.shape.SetAsBox(0.8 * this.LEG_W / 2, this.LEG_H / 2);
        LOWER_FD.density = 1.0;
        LOWER_FD.restitution = 0.0;
        LOWER_FD.filter.categoryBits = 0x20;
        LOWER_FD.filter.maskBits = 0x000F;

        /* Creates the different bodies */

        // Main body
        let main_body_bd = new b2.BodyDef();
        main_body_bd.type = b2.Body.b2_dynamicBody;
        main_body_bd.position.Set(init_x, init_y);
        let main_body = world.CreateBody(main_body_bd);
        for(let fd of MAIN_BODY_FIXTURES){
            main_body.CreateFixture(fd);
        }
        main_body.color1 = "#803366"; // [0.5, 0.2, 0.4]
        main_body.color2 = "#4D1A33"; // [0.3, 0.1, 0.2]
        main_body.ApplyForceToCenter(new b2.Vec2(force_to_center, 0), true);
        main_body.SetUserData(new CustomBodyUserData(true, this.reset_on_hull_critical_contact, "main_body"));
        this.body_parts.push(main_body);
        this.reference_head_object = main_body;

        // Legs bodies and joints
        let legs_coef = [];
        for(let i = 0; i < this.nb_pairs_of_legs; i++){
            legs_coef.push(+1, -1);
        }
        for(let i of legs_coef){

            // First part of the leg
            let upper_leg_angle = 0.25 * Math.PI * i;
            let upper_leg_x_distance = Math.sin(upper_leg_angle) * this.LEG_H / 2;
            let upper_leg_y_distance = Math.cos(upper_leg_angle) * this.LEG_H / 2;
            let upper_leg_x = init_x - i * MAIN_BODY_BOTTOM_WIDTH / this.SCALE / 2 - upper_leg_x_distance;
            let upper_leg_y = init_y + upper_leg_y_distance - this.LEG_DOWN;

            let upper_leg_bd = new b2.BodyDef();
            upper_leg_bd.type = b2.Body.b2_dynamicBody;
            upper_leg_bd.position.Set(upper_leg_x, upper_leg_y);
            upper_leg_bd.angle = upper_leg_angle;
            let upper_leg = world.CreateBody(upper_leg_bd);
            upper_leg.CreateFixture(LEG_FD);
            upper_leg.color1 = "#B36699"; // [0.7, 0.4, 0.6]
            upper_leg.color2 = "#804D66"; // [0.5, 0.3, 0.4]
            upper_leg.SetUserData(new CustomBodyUserData(false, false,"upper_leg"));
            this.body_parts.push(upper_leg);

            // Upper leg joint motor
            let upper_leg_rjd = new b2.RevoluteJointDef();
            upper_leg_rjd.Initialize(main_body, upper_leg, new b2.Vec2(init_x - i * MAIN_BODY_BOTTOM_WIDTH / this.SCALE / 2, init_y - this.LEG_DOWN));
            upper_leg_rjd.enableMotor = true;
            upper_leg_rjd.enableLimit = true;
            upper_leg_rjd.maxMotorTorque = this.MOTORS_TORQUE;
            upper_leg_rjd.motorSpeed = 1;
            upper_leg_rjd.lowerAngle = - 0.1 * Math.PI;
            upper_leg_rjd.upperAngle = 0.1 * Math.PI;
            let joint_motor = world.CreateJoint(upper_leg_rjd);
            joint_motor.SetUserData(new CustomMotorUserData("hip", SPIDER_SPEED_HIP, false));
            this.motors.push(joint_motor);

            // Second part of the leg
            let middle_leg_angle = 0.7 * Math.PI * i;
            let middle_leg_x_distance = Math.sin(middle_leg_angle) * this.LEG_H / 2;
            let middle_leg_y_distance = - Math.cos(middle_leg_angle) * this.LEG_H / 2;
            let middle_leg_x = upper_leg_x - upper_leg_x_distance - middle_leg_x_distance;
            let middle_leg_y = upper_leg_y + upper_leg_y_distance - middle_leg_y_distance;

            let middle_leg_bd = new b2.BodyDef();
            middle_leg_bd.type = b2.Body.b2_dynamicBody;
            middle_leg_bd.position.Set(middle_leg_x, middle_leg_y);
            middle_leg_bd.angle = middle_leg_angle;
            let middle_leg = world.CreateBody(middle_leg_bd);
            middle_leg.CreateFixture(LEG_FD);
            middle_leg.color1 = "#B36699"; // [0.7, 0.4, 0.6]
            middle_leg.color2 = "#804D66"; // [0.5, 0.3, 0.4]
            middle_leg.SetUserData(new CustomBodyUserData(false, false,"middle_leg"));
            this.body_parts.push(middle_leg);

            // middle_leg joint motor
            let middle_leg_rjd = new b2.RevoluteJointDef();
            middle_leg_rjd.Initialize(upper_leg, middle_leg, new b2.Vec2(upper_leg_x - upper_leg_x_distance, upper_leg_y + upper_leg_y_distance));
            middle_leg_rjd.enableMotor = true;
            middle_leg_rjd.enableLimit = true;
            middle_leg_rjd.maxMotorTorque = this.MOTORS_TORQUE;
            middle_leg_rjd.motorSpeed = 1;
            middle_leg_rjd.lowerAngle = - 0.15 * Math.PI;
            middle_leg_rjd.upperAngle = 0.15 * Math.PI;
            joint_motor = world.CreateJoint(middle_leg_rjd);
            joint_motor.SetUserData(new CustomMotorUserData("hip", SPIDER_SPEED_HIP,false));
            this.motors.push(joint_motor);

            // Third part of the leg
            let lower_leg_angle = 0.9 * Math.PI * i;
            let lower_leg_x_distance = Math.sin(lower_leg_angle) * this.LEG_H / 2;
            let lower_leg_y_distance = - Math.cos(lower_leg_angle) * this.LEG_H / 2;
            let lower_leg_x = middle_leg_x - middle_leg_x_distance - lower_leg_x_distance;
            let lower_leg_y = middle_leg_y - middle_leg_y_distance - lower_leg_y_distance;

            let lower_leg_bd = new b2.BodyDef();
            lower_leg_bd.type = b2.Body.b2_dynamicBody;
            lower_leg_bd.position.Set(lower_leg_x, lower_leg_y);
            lower_leg_bd.angle = lower_leg_angle;
            let lower_leg = world.CreateBody(lower_leg_bd);
            lower_leg.CreateFixture(LOWER_FD);
            lower_leg.color1 = "#B36699"; // [0.7, 0.4, 0.6]
            lower_leg.color2 = "#804D66"; // [0.5, 0.3, 0.4]
            lower_leg.SetUserData(new CustomBodyUserData(true, false,"lower_leg"));
            this.body_parts.push(lower_leg);

            // lower_leg joint motor
            let lower_leg_rjd = new b2.RevoluteJointDef();
            lower_leg_rjd.Initialize(middle_leg, lower_leg, new b2.Vec2(middle_leg_x - middle_leg_x_distance, middle_leg_y - middle_leg_y_distance));
            lower_leg_rjd.enableMotor = true;
            lower_leg_rjd.enableLimit = true;
            lower_leg_rjd.maxMotorTorque = this.MOTORS_TORQUE;
            lower_leg_rjd.motorSpeed = 1;
            lower_leg_rjd.lowerAngle = - 0.2 * Math.PI;
            lower_leg_rjd.upperAngle = 0.2 * Math.PI;
            joint_motor = world.CreateJoint(lower_leg_rjd);
            joint_motor.SetUserData(new CustomMotorUserData("knee", SPIDER_SPEED_KNEE,true, 0.0, lower_leg));
            this.motors.push(joint_motor);
        }
    }
};