aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNielsCoding <48092678+heavydemon21@users.noreply.github.com>2023-04-05 20:46:53 +0200
committerNielsCoding <48092678+heavydemon21@users.noreply.github.com>2023-04-05 20:46:53 +0200
commitdc5e246ff1e8d89e59acf70c149f180fb41dd584 (patch)
treede7f2c3849a4ab6889747531452b7963ecf59f8c
parent854a80001b9798d1454e4308e4efba96431e44d8 (diff)
enemy and ai, bullets and gameplay
ai needs finetuning
-rw-r--r--src/demo.c4
-rw-r--r--src/engine/bullet.c40
-rw-r--r--src/engine/enemy.c10
-rw-r--r--src/engine/enemy.h5
-rw-r--r--src/engine/enemy_ai.c99
-rw-r--r--src/engine/enemy_ai.h10
-rw-r--r--src/engine/entity.c31
-rw-r--r--src/engine/entity.h5
-rw-r--r--src/engine/level_const.c2
-rw-r--r--src/engine/player_controller.c2
-rw-r--r--src/engine/types.h4
-rw-r--r--src/game_loop/gameplay.c46
-rw-r--r--src/game_loop/gameplay.h3
-rw-r--r--src/game_loop/starting_screen.c1
-rw-r--r--src/makefile1
15 files changed, 230 insertions, 33 deletions
diff --git a/src/demo.c b/src/demo.c
index aae1729..8e7af93 100644
--- a/src/demo.c
+++ b/src/demo.c
@@ -65,14 +65,16 @@ void hh_demo_loop(unsigned long frame) {
hh_gameplay(&hh_game, &hh_game_states);
break;
case hh_e_state_game_over:
- // todo:
+ // TODO:
// function: show game over screen
// function: after time goto high score
+ hh_game_states = hh_e_state_high_score;
break;
case hh_e_state_high_score:
// todo:
// fucntion: show all previously scored points
// function: button pressed goto starting screen
+ hh_game_states = hh_e_state_starting_screen;
break;
default:
hh_game_states = hh_e_state_starting_screen;
diff --git a/src/engine/bullet.c b/src/engine/bullet.c
index 55b20cc..eb9a8bb 100644
--- a/src/engine/bullet.c
+++ b/src/engine/bullet.c
@@ -42,12 +42,47 @@ bool rising_edge(bool signal, bool* prev) {
return edge;
}
bool prev_signal = false;
+void hh_handle_bullet_direction(hh_entity* bullet){
+ bullet->vel = (vec2){0,0};
+ if (g_hh_controller_p1.dpad_left) {
+ if (g_hh_controller_p1.dpad_up) {
+ bullet->vel.x = -1;
+ bullet->vel.y = -1;
+ } else if (g_hh_controller_p1.dpad_down) {
+ bullet->vel.x = -1;
+ bullet->vel.y = 1;
+ } else {
+ bullet->vel.x = -1;
+ }
+ }else if (g_hh_controller_p1.dpad_right) {
+ if (g_hh_controller_p1.dpad_up) {
+ bullet->vel.x = 1;
+ bullet->vel.y = -1;
+ } else if (g_hh_controller_p1.dpad_down) {
+ bullet->vel.x = 1;
+ bullet->vel.y = 1;
+ } else {
+ bullet->vel.x = 1;
+ }
+ } else if (g_hh_controller_p1.dpad_up){
+ bullet->vel.y = -1;
+ } else if (g_hh_controller_p1.dpad_down){
+ bullet->vel.y = 1;
+ }
+ else{
+ bullet->vel.x = 1;
+ }
+ bullet->render.fam.horizontal_flip = (bullet->vel.x < 0);
+ bullet->render.fam.vertical_flip = (bullet->vel.y != 0);
+
+}
void hh_shoot_bullet(vec2 player, hh_entity* bullet){
vec2 temp;
if(rising_edge(g_hh_controller_p1.button_secondary,&prev_signal) && bullet->is_grounded){
bullet->is_grounded=false;
bullet->pos = player;
current_bullet = (current_bullet + 1) % bullets_size;
+ hh_handle_bullet_direction(bullet);
}
}
@@ -55,11 +90,10 @@ void hh_shoot_bullet(vec2 player, hh_entity* bullet){
void hh_update_bullet(hh_entity* bullet){
if(hh_background_collision_bulllet(*bullet)){
hh_bullet_death(bullet);
-
- // printf("x %d y %d\n",(bullet->pos.x-cam_pos.x),(bullet->pos.y-cam_pos.y));
}
else{
- bullet->pos.x += bullet->speed;
+ bullet->pos.x = bullet->pos.x + bullet->vel.x * bullet->speed;
+ bullet->pos.y = bullet->pos.y + bullet->vel.y * bullet->speed;
}
}
diff --git a/src/engine/enemy.c b/src/engine/enemy.c
index 186cfa0..4ed48a2 100644
--- a/src/engine/enemy.c
+++ b/src/engine/enemy.c
@@ -1,14 +1,9 @@
#include "engine/enemy.h"
-void hh_update_enemy(hh_entity* enemy, vec_cor cam_pos){
- //Bjorn functions
-
-}
-
-void hh_multiple_enemies( vec_cor cam_pos, hh_entity* enemies, int total_enemies){
+void hh_multiple_enemies(hh_entity* enemies, hh_entity player, vec_cor cam_pos, int total_enemies){
for(int i=0; i < total_enemies;i++){
- hh_update_enemy(&enemies[i] , cam_pos);
+ hh_update_enemy(&enemies[i] , player, cam_pos);
}
}
@@ -22,6 +17,7 @@ void hh_enemy_death_check(hh_entity* enemy){
enemy->hp--;
}
}
+
void hh_solve_hitted_enemies(hh_entity* enemies, int total_enemies){
for(int i = 0; i < total_enemies; i++){
if(enemies[i].is_hit){
diff --git a/src/engine/enemy.h b/src/engine/enemy.h
index 80498f5..c8a3f20 100644
--- a/src/engine/enemy.h
+++ b/src/engine/enemy.h
@@ -1,14 +1,13 @@
#pragma once
#include "player_controller.h"
#include "engine/sprite_controller.h"
+#include "engine/enemy_ai.h"
#include "types.h"
#include "input.h"
-/** @brief updates a single enemy locations TODO: Bjorn sets functions in here*/
-void hh_update_enemy(hh_entity* , vec_cor );
/** @brief calculates all the given enemies positions*/
-void hh_multiple_enemies( vec_cor cam_pos, hh_entity* enemies, int total_enemies);
+void hh_multiple_enemies(hh_entity* enemies, hh_entity player, vec_cor cam_pos, int total_enemies);
/** @brief checks if the enemy has zero hp else it takes hp from the enemy */
void hh_enemy_death_check(hh_entity* enemy);
diff --git a/src/engine/enemy_ai.c b/src/engine/enemy_ai.c
new file mode 100644
index 0000000..81d04d9
--- /dev/null
+++ b/src/engine/enemy_ai.c
@@ -0,0 +1,99 @@
+#include "engine/enemy_ai.h"
+
+int8_t hh_get_direction(int32_t player_x, int32_t enemy_x){
+ int movement_direction = player_x - enemy_x; // = player.pos.x - player.prev_pos.x;
+ if (movement_direction > 0) {
+ return 1; // move in positive direction
+ } else if (movement_direction < 0) {
+ return -1; // move in negative direction
+ } else {
+ return 0; // don't move
+ }
+}
+void hh_update_enemy_movement(hh_entity* enemy){
+ hh_entity enemy_new = {0};
+ enemy_new = *enemy;
+ enemy_new.vel = (vec2){
+ .x = enemy->vel.x,
+ .y = enemy->vel.y,
+ };
+
+ enemy_new.pos = (vec2){
+ .x = enemy->pos.x + enemy_new.vel.x,
+ .y = enemy->pos.y + enemy_new.vel.y,
+ };
+
+
+ *enemy = hh_background_collision ( *enemy, enemy_new);
+}
+void hh_slime_ai(hh_entity* enemy, hh_entity player){
+ int8_t direction = hh_get_direction(player.pos.x, enemy->pos.x);
+ if((player.pos.x - enemy->pos.x) >= -hunt_player && (player.pos.x - enemy->pos.x) <= hunt_player){
+ hh_movement_entity(enemy, direction);
+ }
+ hh_gravity_entity(enemy);
+ hh_update_enemy_movement(enemy);
+
+}
+
+void hh_jump_slime_ai(hh_entity* enemy, hh_entity player){
+ int8_t direction = hh_get_direction(player.pos.x, enemy->pos.x);
+ hh_gravity_entity(enemy);
+ if((player.pos.x - enemy->pos.x) >= -hunt_player && (player.pos.x - enemy->pos.x) <= hunt_player){
+ hh_movement_entity(enemy, direction);
+ // TODO: fix this if statement and make it cleaner. this makes the enemy jump when the player mets the condition
+ if((player.pos.y - enemy->pos.y) < -16 && (player.pos.y - enemy->pos.y) >= -100 && (player.pos.x - enemy->pos.x) >= -10 && (player.pos.x - enemy->pos.x) <= 10){
+ hh_jump_entity(enemy);
+ }
+ }
+
+ hh_update_enemy_movement(enemy);
+
+}
+#define terror_owl_attack_timer 100
+#define terror_owl_follow_player_delay 5
+#define terror_owl_attack_player_delay 12
+#define terror_owl_dive_speed 3
+#define delay_frames 2
+#define terror_owl_minimal_distance_from_player 100
+void hh_terror_owl_ai(hh_entity* enemy, hh_entity player){
+ static int count=0;
+ static int last_y_location=0;
+
+ if (count < terror_owl_attack_timer) {
+ // Move towards player position smoothly
+ int delta_x = (-50 + player.pos.x - enemy->pos.x) / terror_owl_follow_player_delay;
+ enemy->pos.x += delta_x;
+ enemy->pos.y = player.pos.y - terror_owl_minimal_distance_from_player;
+
+ count++;
+ last_y_location=player.pos.y;
+ } else {
+ if(enemy->pos.y <= last_y_location){
+ int delta_x = (player.pos.x - enemy->pos.x) / terror_owl_attack_player_delay;
+ enemy->pos.x += delta_x;
+ enemy->pos.y += terror_owl_dive_speed;
+ }
+ else{
+ count = 0;
+ }
+ }
+
+}
+void hh_update_enemy(hh_entity* enemy , hh_entity player, vec_cor cam_pos){
+ // static hh_e_entity_type type;
+ switch (enemy->object_type)
+ {
+ case slime:
+ hh_slime_ai(enemy,player);
+ break;
+ case jumping_slime:
+ hh_jump_slime_ai(enemy,player);
+ break;
+ case terror_owl:
+ hh_terror_owl_ai(enemy,player);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/src/engine/enemy_ai.h b/src/engine/enemy_ai.h
new file mode 100644
index 0000000..d68f50f
--- /dev/null
+++ b/src/engine/enemy_ai.h
@@ -0,0 +1,10 @@
+#pragma once
+#include "player_controller.h"
+#include "engine/sprite_controller.h"
+#include "types.h"
+#include "input.h"
+#include <math.h>
+
+
+#define hunt_player 100
+void hh_update_enemy(hh_entity* enemy , hh_entity player, vec_cor cam_pos);
diff --git a/src/engine/entity.c b/src/engine/entity.c
index 1cb88be..eba6481 100644
--- a/src/engine/entity.c
+++ b/src/engine/entity.c
@@ -43,6 +43,7 @@ void hh_solve_collision(vec2 pos_environment, hh_entity* entity){
// entity->vel.x = 0;
// }
}
+
hh_entity hh_background_collision (hh_entity temp_old_entity,hh_entity temp_new_entity){
temp_new_entity.is_grounded = false;
@@ -119,6 +120,7 @@ bool hh_background_collision_bulllet (hh_entity temp_old_entity){
// temp_old_entity.vel = temp_new_entity.vel;
return false;
}
+
hh_entity hh_enemy_collision(hh_entity temp_player, hh_entity temp_enemy){
bool collide = hh_distance_circles( temp_player.pos, temp_enemy.pos, temp_player.radius, temp_enemy.radius);
@@ -138,7 +140,7 @@ hh_entity hh_enemy_collision(hh_entity temp_player, hh_entity temp_enemy){
temp_player.vel.x = 8;
}
// ghost mode / invulnerable or other things on hit
- // temp_player.hp--;
+ temp_player.hp--;
} else {
temp_player.is_hit = false;
@@ -170,14 +172,35 @@ void hh_jump_entity(hh_entity* object_1){
}
}
void hh_gravity_entity(hh_entity* object_1){
- if (object_1->is_grounded == false && object_1->vel.y < 6) {
+ if (object_1->is_grounded == false) {
object_1->vel.y += 1; //gravity
}
}
-void hh_hit_entity(hh_entity* object_1, int8_t* hit_timer, int8_t* direction){
+
+void hh_movement_entity(hh_entity* object_1, int8_t* direction){
+ if(direction != 0){
+ if(object_1->vel.x > -1 * object_1->speed && object_1->vel.x < object_1->speed) {
+ object_1->vel.x = object_1->vel.x + direction;
+ } else {
+ if (object_1->vel.x > 0) {
+ object_1->vel.x--;
+ } else if(object_1->vel.x < 0) {
+ object_1->vel.x++;
+ }
+ }
+ } else {
+ if (object_1->vel.x > 0) {
+ object_1->vel.x--;
+ } else if(object_1->vel.x < 0) {
+ object_1->vel.x++;
+ }
+ }
+
+}
+void hh_player_move_hit(hh_entity* object_1, int8_t* hit_timer, int8_t* direction){
if(object_1->is_hit == true){
hit_timer = 9;
- object_1->is_hit = false;
+ //object_1->is_hit = false;
}
if(hit_timer > -10){
hit_timer--;
diff --git a/src/engine/entity.h b/src/engine/entity.h
index fde9341..fb1c905 100644
--- a/src/engine/entity.h
+++ b/src/engine/entity.h
@@ -51,9 +51,12 @@ void hh_jump_entity(hh_entity* );
/** @brief looks if the player is grounded and if not it sets the position down */
void hh_gravity_entity(hh_entity* );
/** @brief if object is hit bounches in specific direction and moves the object */
-void hh_hit_entity(hh_entity* object_1, int8_t* hit_timer, int8_t* direction);
+void hh_player_move_hit(hh_entity* object_1, int8_t* hit_timer, int8_t* direction);
+
+void hh_movement_entity(hh_entity* object_1, int8_t* direction);
/** @brief specific bullet background collisions detection */
bool hh_background_collision_bulllet (hh_entity temp_old_entity);
/** @brief checks any entity has a hit on each othe*/
void hh_check_all_collisions(hh_entity* player, hh_entity* enemies, int total_enemies, hh_entity* bullets, int total_bullets, vec_cor cam_pos);
+
diff --git a/src/engine/level_const.c b/src/engine/level_const.c
index 896d0e0..a6a7c84 100644
--- a/src/engine/level_const.c
+++ b/src/engine/level_const.c
@@ -4,7 +4,7 @@
hh_g_all_levels hh_init_game_levels(){
hh_g_all_levels levels;
- levels.current_level=0;
+ levels.current_level=1;
levels.level[0].size.x=40;
levels.level[0].size.y=100;
diff --git a/src/engine/player_controller.c b/src/engine/player_controller.c
index 83c5966..5b0da99 100644
--- a/src/engine/player_controller.c
+++ b/src/engine/player_controller.c
@@ -16,7 +16,7 @@ void hh_player_actions(hh_entity* player){
int8_t direction_x = (-1 * g_hh_controller_p1.dpad_left) + (1 * g_hh_controller_p1.dpad_right);
int8_t direction_y = (-1 * g_hh_controller_p1.dpad_up) + (1 * g_hh_controller_p1.dpad_down);
- hh_hit_entity(player,hit_timer,direction_x);
+ hh_player_move_hit(player,hit_timer,direction_x);
hh_gravity_entity(player);
if(g_hh_controller_p1.button_primary){
hh_jump_entity(player);
diff --git a/src/engine/types.h b/src/engine/types.h
index 00b381b..8040e46 100644
--- a/src/engine/types.h
+++ b/src/engine/types.h
@@ -4,6 +4,9 @@
typedef uint8_t hh_ppu_fg_idx;
// typedef uint16_t hh_bg_idx;
+typedef enum {
+ slime, jumping_slime, terror_owl,
+}hh_e_all_objects_game_type;
typedef enum {
fire, ice, poison
@@ -31,6 +34,7 @@ typedef struct {
vec2 pos, vel, size;
bool is_grounded;
bool is_hit;
+ hh_e_all_objects_game_type object_type;
uint8_t radius;
int8_t hp;
int8_t speed;
diff --git a/src/game_loop/gameplay.c b/src/game_loop/gameplay.c
index da029f3..b7da04f 100644
--- a/src/game_loop/gameplay.c
+++ b/src/game_loop/gameplay.c
@@ -1,6 +1,5 @@
#include "gameplay.h"
#include "engine/entity.h"
-// player struct
void hh_gameplay(hh_g_all_levels* game, hh_e_game_state* hh_game_state){
@@ -11,7 +10,7 @@ void hh_gameplay(hh_g_all_levels* game, hh_e_game_state* hh_game_state){
.speed = 6,
.is_grounded = false,
.is_hit = false,
- .radius = 8,
+ .radius = 16,
.pos = (vec2){32,32},
.size = (vec2){32,32},
.vel = (vec2){0,0},
@@ -28,12 +27,13 @@ void hh_gameplay(hh_g_all_levels* game, hh_e_game_state* hh_game_state){
};
// enemy gets replaced here is just for reference
static hh_entity enemy={
+ .object_type = jumping_slime,
.hp = 4,
- .speed = 6,
+ .speed = 2,
.is_grounded = false,
.is_hit = false,
.radius = 8,
- .pos = (vec2){128,24},
+ .pos = (vec2){200,200},
.size = (vec2){16,16},
.vel = (vec2){0,0},
// .vec = (vec2){0,0},
@@ -52,19 +52,17 @@ void hh_gameplay(hh_g_all_levels* game, hh_e_game_state* hh_game_state){
switch (gameplay)
{
case hh_e_setup_screen:
- printf("%d\n",game->current_level);
bullets = hh_init_bullets(total_bullets);
hh_setup_screen(game->level[game->current_level]);
gameplay = hh_e_play_level;
- enemy.hp=4;
break;
case hh_e_play_level:
- // TODO: here come all the different functions for the gameplay
- vec_cor cam_pos;//value in tiles
+
+ vec_cor cam_pos;
cam_pos = hh_draw_screen(player1.pos);
hh_player_actions(&player1);
hh_multiple_bullets(player1.pos,bullets);
- hh_multiple_enemies(cam_pos, &enemy,1);
+ hh_multiple_enemies(&enemy, player1, cam_pos, 1);
hh_check_all_collisions(&player1,&enemy,1,bullets,total_bullets,cam_pos);
hh_solve_hitted_enemies(&enemy,1);
hh_render_all_entities(&player1,bullets,&enemy,total_bullets,1, cam_pos);
@@ -74,19 +72,24 @@ void hh_gameplay(hh_g_all_levels* game, hh_e_game_state* hh_game_state){
if(game->level[game->current_level].hh_level_completed){
gameplay = hh_e_level_complete;
}
+ else if(player1.hp == 0){
+ gameplay = hh_e_game_over;
+ }
break;
case hh_e_level_complete:
+ // TODO: from complete to shop or game_over
if(game->current_level < 3){
game->current_level+=1;
gameplay = hh_e_setup_screen;
}
else {
+
gameplay = hh_e_game_over;
}
break;
case hh_e_game_over:
// todo make reset levels
- hh_reset_levels();
+ hh_reset_levels(&player1);
gameplay = hh_e_setup_screen;
*hh_game_state = hh_e_state_game_over;
break;
@@ -95,7 +98,28 @@ void hh_gameplay(hh_g_all_levels* game, hh_e_game_state* hh_game_state){
}
}
-void hh_reset_levels(){}
+void hh_reset_levels(hh_entity* player){
+ *player = (hh_entity){
+ .hp = 4,
+ .speed = 6,
+ .is_grounded = false,
+ .is_hit = false,
+ .radius = 16,
+ .pos = (vec2){32,32},
+ .size = (vec2){32,32},
+ .vel = (vec2){0,0},
+ .render = {
+ .frame0 = 3,
+ .palette = 3,
+ .fam = (hh_s_ppu_loc_fam_entry){
+ .horizontal_flip = false,
+ .vertical_flip = false,
+ .palette_index = 3,
+ .tilemap_index = 80,
+ }
+ }
+ };
+}
void hh_render_all_entities(hh_entity* player, hh_entity* bullets, hh_entity* enemies, int bullet_size, int enemy_size, vec_cor cam_pos){
diff --git a/src/game_loop/gameplay.h b/src/game_loop/gameplay.h
index 9d66c37..8adddb4 100644
--- a/src/game_loop/gameplay.h
+++ b/src/game_loop/gameplay.h
@@ -15,8 +15,9 @@ typedef enum {
hh_e_level_complete,
hh_e_game_over,
}hh_e_gameplay;
+
/** @brief resets all the levels the first condition */
-void hh_reset_levels();
+void hh_reset_levels(hh_entity* player);
/** @brief game loop function to handle the gameplay*/
void hh_gameplay(hh_g_all_levels* game, hh_e_game_state* hh_game_state);
/** @brief renders all the entities*/
diff --git a/src/game_loop/starting_screen.c b/src/game_loop/starting_screen.c
index c11e4fc..d9f8ea6 100644
--- a/src/game_loop/starting_screen.c
+++ b/src/game_loop/starting_screen.c
@@ -11,6 +11,7 @@ bool hh_show_starting_screen(){
{
case hh_e_state_show:
hh_clear_screen();
+ hh_clear_sprite();
hh_init_title_screen();
hh_e_starting_screen = hh_e_state_input;
return false;
diff --git a/src/makefile b/src/makefile
index fdd8ab5..7f2cdc1 100644
--- a/src/makefile
+++ b/src/makefile
@@ -42,6 +42,7 @@ LOCAL_SRCS += main.c \
engine/title_screen.c \
engine/level_const.c \
engine/enemy.c \
+ engine/enemy_ai.c \
engine/animator.c \
game_loop/shop.c \
game_loop/gameplay.c \