20 Player::Player(GameState &state, Vector position, bool visible) : |
20 Player::Player(GameState &state, Vector position, bool visible) : |
21 PhysicsObject(state.world, PLAYER_MASS, position, Vector(0, 0)), state(state), visible(visible), arsenal(), selectedWeapon(0), changing(false), animation_step(0) { |
21 PhysicsObject(state.world, PLAYER_MASS, position, Vector(0, 0)), state(state), visible(visible), arsenal(), selectedWeapon(0), changing(false), animation_step(0) { |
22 // TODO: arsenal's size should be affected by some value |
22 // TODO: arsenal's size should be affected by some value |
23 // and weapons should be loaded from somewhere, not generated here |
23 // and weapons should be loaded from somewhere, not generated here |
24 for (int i = 0; i < 5; i++) { |
24 for (int i = 0; i < 5; i++) { |
25 arsenal.push_back(Weapon(10000, (5-i)*40+30, i*6+5, i*100+50, "asdf")); |
25 arsenal.push_back(Weapon(state, 10000, (5 - i) * 40 + 30, i * 6 + 5, i * 100 + 50, "asdf")); |
26 } |
26 } |
27 |
27 |
28 // build the player's shape |
28 // build the player's shape |
29 // XXX: these dimensions are incorrect... |
29 // XXX: these dimensions are incorrect... |
30 std::vector<Vector> shape(4); |
30 std::vector<Vector> shape(4); |
50 Vector shotVelocity = unitVectorAim*shotspeed; |
50 Vector shotVelocity = unitVectorAim*shotspeed; |
51 new Projectile(this->state, this->position, shotVelocity, false, radius, 1); |
51 new Projectile(this->state, this->position, shotVelocity, false, radius, 1); |
52 |
52 |
53 } |
53 } |
54 |
54 |
55 void Player::debugInfo (void) { |
55 void Player::handleShoot (Weapon &weapon) { |
56 Engine::log(DEBUG, "Player.debugInfo") << "In air: " << this->inAir; |
56 Vector unitVectorAim = (facingRight ? |
57 } |
57 Vector(std::cos(aim), -std::sin(aim)) : |
58 |
58 Vector(-std::cos(aim), -std::sin(aim)) |
59 /** |
59 ); |
60 * shoots the selected weapon. |
60 |
61 * TODO: selection and weapon information |
61 // XXX: what does the PHYSICS_TICK_MS stuff mean? |
62 */ |
62 float shotspeed = weapon.getVelocity() * PHYSICS_TICK_MS / 2; |
63 void LocalPlayer::shoot (void) { |
63 |
64 // here should be somehow considered which projectile it is |
|
65 if(!canShoot()) |
|
66 return; |
|
67 reloadTimer += getWeapon().reloadTime; |
|
68 Vector unitVectorAim = facingRight ? Vector(std::cos(aim), -std::sin(aim)) : |
|
69 Vector(-std::cos(aim), -std::sin(aim)); |
|
70 float shotspeed = getWeapon().velocity*PHYSICS_TICK_MS/2; |
|
71 Vector shotRelativeVelocity = unitVectorAim * shotspeed; |
64 Vector shotRelativeVelocity = unitVectorAim * shotspeed; |
72 Vector shotVelocity = this->velocity + shotRelativeVelocity; |
65 Vector shotVelocity = this->velocity + shotRelativeVelocity; |
73 Vector shotPosition = this->position + unitVectorAim*10; |
66 Vector shotPosition = this->position + unitVectorAim * 10; |
74 new Projectile(this->state, shotPosition, shotVelocity, true, getWeapon().explosionRadius); |
67 |
75 } |
68 weapon.shoot(shotPosition, shotVelocity); |
76 |
69 } |
77 void LocalPlayer::handleMove (PlayerInput_Move input) { |
70 |
78 float fx = 0; // Force in x-direction |
71 void Player::printDebugInfo (void) { |
79 float da = 0; // Crosshair angle |
72 Engine::log(DEBUG, "layer.debug") << "In air: " << this->inAir; |
80 |
73 } |
81 // handle left/right |
74 |
82 if ((input & INPUT_MOVE_LEFT) && (velocity.x > -PLAYER_MAX_SPEED)) |
75 void Player::tick (TimeMS dt) { |
83 fx -= PLAYER_MOVE_FORCE; |
76 // let PhysicsObject execute |
84 |
77 PhysicsObject::tick(dt); |
85 if ((input & INPUT_MOVE_RIGHT) && (velocity.x < PLAYER_MAX_SPEED)) |
78 |
86 fx += PLAYER_MOVE_FORCE; |
79 // tick current weapon reload |
87 |
80 getWeapon().tickReload(dt); |
88 if (input & INPUT_MOVE_UP) |
81 } |
89 da += CROSSHAIR_ANGLE_SPEED; |
82 |
90 |
83 void LocalPlayer::handleInput (PlayerInput input) { |
91 if (input & INPUT_MOVE_DOWN) |
84 // Movement force, vertical is always zero |
92 da -= CROSSHAIR_ANGLE_SPEED; |
85 Vector move_force = Vector(0, 0); |
93 |
86 |
94 if (input & INPUT_MOVE_JUMP) { |
87 // Crosshair angle change |
95 if ((input & INPUT_MOVE_LEFT)) |
88 float aim_delta = 0; |
|
89 |
|
90 // handle movement left/right by applying a horizontal force, but limit the player's speed |
|
91 if ((input & INPUT_MOVE_LEFT) && (velocity.x > -PLAYER_MAX_SPEED)) { |
|
92 setFacing(false); |
|
93 move_force.x -= PLAYER_MOVE_FORCE; |
|
94 |
|
95 } |
|
96 |
|
97 if ((input & INPUT_MOVE_RIGHT) && (velocity.x < PLAYER_MAX_SPEED)) { |
|
98 setFacing(true); |
|
99 move_force.x += PLAYER_MOVE_FORCE; |
|
100 } |
|
101 |
|
102 // handle aim by creating a aim angle delta |
|
103 if (input & INPUT_AIM_UP) |
|
104 aim_delta += CROSSHAIR_ANGLE_SPEED; |
|
105 |
|
106 if (input & INPUT_AIM_DOWN) |
|
107 aim_delta -= CROSSHAIR_ANGLE_SPEED; |
|
108 |
|
109 // handle jumping by invoking the jump method |
|
110 // XXX: the direction should ideally be given using some other method |
|
111 if (input & INPUT_JUMP) { |
|
112 if (input & INPUT_MOVE_LEFT) |
96 jump(-1); |
113 jump(-1); |
97 else if ((input & INPUT_MOVE_RIGHT)) |
114 |
|
115 else if (input & INPUT_MOVE_RIGHT) |
98 jump(1); |
116 jump(1); |
|
117 |
99 else |
118 else |
100 jump(0); |
119 jump(0); |
101 } |
120 } |
102 |
121 |
103 if (input & INPUT_MOVE_DIG) { |
122 // outsource digging to Player::handleDig, since this modifies the Terrain and Network needs to know |
|
123 if (input & INPUT_DIG) { |
|
124 handleDig(position, 15); |
|
125 |
104 // Should create Projectile which destroys ground, but also should be destroyed then, |
126 // Should create Projectile which destroys ground, but also should be destroyed then, |
105 // but it doesn't. |
127 // but it doesn't. |
106 // But this now just segfaults |
128 // But this now just segfaults |
107 // world.addObject(new Projectile(state, position, true)); |
129 // world.addObject(new Projectile(state, position, true)); |
108 |
130 } |
109 handleDig(position, 15); |
131 |
110 } |
132 // XXX: currently not network safe |
111 |
|
112 if (input & INPUT_CHANGE) { |
133 if (input & INPUT_CHANGE) { |
113 if(changing) { |
134 if (changing) { |
114 |
135 |
115 } else { |
136 } else { |
116 changing = true; |
137 changing = true; |
117 selectedWeapon = (selectedWeapon+1)%arsenal.size(); |
138 selectedWeapon = (selectedWeapon + 1) % arsenal.size(); |
118 Engine::log(DEBUG, "Player.cc:input ") << "changed weapon " << selectedWeapon; |
139 Engine::log(DEBUG, "Player.cc:input ") << "changed weapon " << selectedWeapon; |
119 } |
140 } |
120 } else { |
141 } else { |
121 changing = false; |
142 changing = false; |
122 } |
143 } |
123 |
144 |
124 if (input & INPUT_SHOOT) { |
145 // validate shoot events, and then outsource to handleShoot so Network can intercept it |
125 this->shoot(); |
146 if (input & INPUT_SHOOT && getWeapon().canShoot()) { |
126 } |
147 this->handleShoot(getWeapon()); |
127 |
148 } |
128 |
149 |
129 |
150 // XXX: how should this be written? |
130 // Player facing |
151 if (move_force.x != 0) |
131 if (fx < 0) setFacing(false); |
152 animation_step = (animation_step + 1) % img_num_step; |
132 else if (fx > 0) setFacing(true); |
153 |
133 |
154 // apply aim delta |
134 if (fx != 0) animation_step = (animation_step+1)%img_num_step; |
155 if (aim_delta) |
135 |
156 changeAim(aim_delta); |
136 |
157 |
137 this->changeAim(da); // Move crosshair |
158 // apply force |
138 |
159 if (!move_force.zero()) |
139 // Apply force |
160 applyForce(move_force); |
140 applyForce(Vector(fx, 0)); |
|
141 |
|
142 } |
161 } |
143 |
162 |
144 Weapon& Player::getWeapon() { |
163 Weapon& Player::getWeapon() { |
145 return arsenal[selectedWeapon%arsenal.size()]; |
164 return arsenal[selectedWeapon % arsenal.size()]; |
146 } |
165 } |
147 |
166 |
148 void Player::draw(CL_GraphicContext *gc) { |
167 void Player::draw (CL_GraphicContext *gc) { |
149 int aim_img_idx = (int)((1 - (getAim()+KG_PI/2)/KG_PI)*img_num_aim); |
168 int aim_img_idx = (int)((1 - (getAim()+KG_PI/2)/KG_PI)*img_num_aim); |
150 int step_img_idx = animation_step%img_num_step; |
169 int step_img_idx = animation_step%img_num_step; |
151 |
170 |
152 // load skin image if not yet loaded |
171 // load skin image if not yet loaded |
153 if (!skin_loaded) { |
172 if (!skin_loaded) { |
154 skin_surface = CL_Surface(PLAYER_SKIN_PATH); |
173 skin_surface = CL_Surface(PLAYER_SKIN_PATH); |
155 skin_loaded = true; |
174 skin_loaded = true; |
156 } |
175 } |
157 |
176 |
|
177 // XXX: this logic looks weird |
158 CL_Rectf destination(position.x - 4, position.y - 4, position.x + 5, position.y + 4); |
178 CL_Rectf destination(position.x - 4, position.y - 4, position.x + 5, position.y + 4); |
159 |
179 |
160 if (!getFacing()) { |
180 if (!getFacing()) { |
161 destination = CL_Rect(position.x + 5, position.y - 4, position.x - 4, position.y + 4); |
181 destination = CL_Rect(position.x + 5, position.y - 4, position.x - 4, position.y + 4); |
162 } |
182 } |
163 |
183 |
164 skin_surface.draw_subpixel( |
184 skin_surface.draw_subpixel( |
165 CL_Rectf(1+step_img_idx*img_width, aim_img_idx*img_height+1, 1+(1+step_img_idx)*img_width, (aim_img_idx+1)*img_height+1), |
185 CL_Rectf( |
166 destination, |
186 1 + step_img_idx * img_width, |
167 gc); |
187 aim_img_idx * img_height + 1, |
|
188 1 + (1 + step_img_idx) * img_width, |
|
189 (aim_img_idx + 1) * img_height + 1 |
|
190 ), |
|
191 destination, gc |
|
192 ); |
168 |
193 |
169 const uint16_t chlen = 10; |
194 const uint16_t chlen = 10; |
170 uint16_t x = position.x; |
195 uint16_t x = position.x; |
171 uint16_t y = position.y; |
196 uint16_t y = position.y; |
172 |
197 |