diff options
Diffstat (limited to 'player.c')
| -rw-r--r-- | player.c | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/player.c b/player.c new file mode 100644 index 0000000..9a05971 --- /dev/null +++ b/player.c @@ -0,0 +1,326 @@ +/* + * player.c -- Implementa el personaje controlado por el jugador. + * Copyright (C) 2018 Juan Marín Noguera + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */
+#include <malloc.h> +#include "collision_type.h" +#include "block.h" +#include "error.h" +#include "player.h" +#include "screen.h" + +#define PLAYER_GRAVITY 0.15 +#define PLAYER_ACCEL 0.2 +#define PLAYER_ACCEL_FLYING 0.02 +#define PLAYER_VELOCITY_JUMP 4.5 +#define PLAYER_MAX_VELOCITY 1.8 +#define PLAYER_ANIM_TICKS 5 +#define PLAYER_ANIM_NO 3 +#define PLAYER_PICT_FILE "50365.bmp" +#define PLAYER_SMALL_Y 34 +#define PLAYER_SMALL_H 16 +#define PLAYER_BIG_Y 1 +#define PLAYER_BIG_H 32 +#define PLAYER_FLOWER_Y 129 +#define PLAYER_SHIFT_X 17 +#define PLAYER_DEAD_X 182 +#define PLAYER_LOOK_X 80 +#define PLAYER_JUMP_X 165 +#define PLAYER_GROUND_X 182 +#define PLAYER_WALK_X 97 +#define PLAYER_VULNERABLE_TICKS 60 + +struct Player { + double x; + double y; + double vx; + double vy; + PlayerState state; + PlayerPos pos; + int left; + int counter; + int coins; + int lives; + int vuln; +}; + +Picture player_pict = NULL; + +Player player_create(int x, int y, int lives) +{ + Player p = malloc(sizeof(struct Player)); + if (p == NULL) + error_libc_exit(); + + p->x = x; + p->y = y; + p->vx = 0; + p->vy = 0; + p->state = PLAYER_ST_SMALL; + p->pos = PLAYER_POS_UPRIGHT; + p->counter = 0; + p->left = 0; + p->coins = 0; + p->lives = lives; + p->vuln = PLAYER_VULNERABLE_TICKS; + + return p; +} + +void player_free(Player p) +{ + if(p == NULL) + error_exit(ERR_NULL_PARAM); + free(p); +} + +void player_end() +{ + if (player_pict != NULL) { + screen_free_picture(player_pict); + player_pict = NULL; + } +} + +double player_x(Player p) +{ + return p->x; +} + +void player_set_x(Player p, double x) +{ + p->x = x; +} + +double player_y(Player p) +{ + return p->y; +} + +void player_set_y(Player p, double y) +{ + p->y = y; +} + +double player_vx(Player p) +{ + return p->vx; +} + +double player_vy(Player p) +{ + return p->vy; +} + +PlayerState player_state(Player p) +{ + return p->state; +} + +PlayerPos player_pos(Player p) +{ + return p->pos; +} + +void player_set_pos(Player p, PlayerPos pos) +{ + if (pos == PLAYER_POS_JUMP && p->pos != PLAYER_POS_JUMP) + p->vy = PLAYER_VELOCITY_JUMP; + p->pos = pos; +} + +int player_coins(Player p) +{ + return p->coins; +} + +int player_lives(Player p) +{ + return p->lives; +} + +void player_update(Player p) +{ + p->counter++; + p->vuln++; + p->vy -= PLAYER_GRAVITY; + p->x += p->vx; + p->y += p->vy; +} + +int player_vulnerable(Player p) +{ + return p->vuln >= PLAYER_VULNERABLE_TICKS; +} + +void player_correct_on_collision(Player p, int dir) +{ + if (dir & COLLISION_BOTTOM) { + p->vy = 0; + p->y = ((int)(p->y + BLOCK_SIZE) / BLOCK_SIZE) * BLOCK_SIZE; + if (dir & COLLISION_TOP) + p->pos = PLAYER_POS_GROUND; + else + p->pos = PLAYER_POS_UPRIGHT; + } else if (dir & COLLISION_TOP) { + p->vy = 0; + p->y = p->y - 2 * (((int)p->y) % BLOCK_SIZE); + } + if (dir & COLLISION_LEFT) { + p->vx = 0; + p->x = (((int)(p->x + BLOCK_SIZE)) / BLOCK_SIZE) * BLOCK_SIZE; + } + if (dir & COLLISION_RIGHT) { + p->vx = 0; + p->x = (((int)(p->x)) / BLOCK_SIZE) * BLOCK_SIZE; + } +} + +void player_accel(Player p, int left) +{ + double amount = p->pos == PLAYER_POS_JUMP && p->vy < 0 ? + PLAYER_ACCEL_FLYING : PLAYER_ACCEL; + if (left) + p->vx = (p->vx > 0 ? -amount : p->vx - amount); + else + p->vx = (p->vx < 0 ? amount : p->vx + amount); + + if (p->vx > PLAYER_MAX_VELOCITY) + p->vx = PLAYER_MAX_VELOCITY; + else if (p->vx < -PLAYER_MAX_VELOCITY) + p->vx = -PLAYER_MAX_VELOCITY; +} + +void player_jump(Player p) +{ + if (p->pos != PLAYER_POS_JUMP) { + p->vy = PLAYER_VELOCITY_JUMP; + p->pos = PLAYER_POS_JUMP; + } +} + + +void player_stop(Player p) +{ + if (p->pos != PLAYER_POS_JUMP) + p->vx = 0; +} + +int player_pict_y(Player p) +{ + switch (p->state) { + case PLAYER_ST_SMALL: + case PLAYER_ST_DEAD: + return PLAYER_SMALL_Y; + case PLAYER_ST_BIG: + return PLAYER_BIG_Y; + case PLAYER_ST_FLOWER: + return PLAYER_FLOWER_Y; + default: + error_exit(ERR_OUT_OF_RANGE); + return 0; // Execution will never reach this point. + } +} + +int player_height(Player p) { + return p->state == PLAYER_ST_SMALL || p->state == PLAYER_ST_DEAD ? + PLAYER_SMALL_H : PLAYER_BIG_H; +} + +int player_pict_x(Player p) +{ + if (p->state == PLAYER_ST_DEAD) + return PLAYER_DEAD_X; + else if (p->pos == PLAYER_POS_JUMP) + return PLAYER_JUMP_X; + else if (p->pos == PLAYER_POS_GROUND && + p->state != PLAYER_ST_SMALL) + return PLAYER_GROUND_X; + else if (p->vx == 0) + return PLAYER_LOOK_X; + else // Walking + return PLAYER_WALK_X + + ((p->counter / PLAYER_ANIM_TICKS) % PLAYER_ANIM_NO) + * PLAYER_SHIFT_X; +} + +void player_render(Screen scr, Player p, int scroll) +{ + int h = player_height(p); + + if (p->vx < 0) + p->left = 1; + else if (p->vx > 0) + p->left = 0; + + if (player_pict == NULL) + player_pict = screen_get_picture(PLAYER_PICT_FILE); + + screen_place( + scr, + player_pict, + p->x - scroll, + screen_height(scr) - p->y - h, + player_pict_x(p), + player_pict_y(p), + PLAYER_WIDTH, + h, + p->left); +} + +void player_downgrade(Player p) +{ + if (p->state != PLAYER_ST_DEAD) + p->state--; + p->vuln = 0; +} + +void player_upgrade_to(Player p, int state) +{ + if (p->state > PLAYER_ST_FLOWER) + error_exit(ERR_OUT_OF_RANGE); + if (p->state < state) + p->state = state; +} + +void player_die(Player p) +{ + p->state = PLAYER_ST_DEAD; +} + +void player_add_coin(Player p) +{ + if (++p->coins % 100 == 0) + ++p->lives; +} + + +int player_restart(Player p) +{ + p->vx = 0; + p->vy = 0; + p->pos = PLAYER_POS_UPRIGHT; + p->left = 0; + p->counter = 0; + p->vuln = PLAYER_VULNERABLE_TICKS; + + if (p->state == PLAYER_ST_DEAD) { + player_upgrade_to(p, PLAYER_ST_SMALL); + p->coins = 0; + } + + return --p->lives > 0; +} |
