Movement 1
This commit is contained in:
parent
26018facea
commit
ab5c442433
7
game/NOTES.md
Normal file
7
game/NOTES.md
Normal file
@ -0,0 +1,7 @@
|
||||
Some notes on the game
|
||||
|
||||
# Position and velocity
|
||||
|
||||
All positions are represented in fixed-point fashion, with a precision of 256.
|
||||
|
||||
For instance, a position or distance of 8 pixels is represented as `0x800`. (2048)
|
29
game/game.c
29
game/game.c
@ -4,9 +4,20 @@
|
||||
#include "map/game_map.h"
|
||||
#include "game.h"
|
||||
#include "sys/sys.h"
|
||||
#include <stdio.h>
|
||||
|
||||
uint32_t game_frame;
|
||||
|
||||
game_bbox game_player_bbox = {
|
||||
.x=0x9000,
|
||||
// .y=0x5800,
|
||||
.y=0x0000,
|
||||
.w=0x1000,
|
||||
.h=0x1000,
|
||||
};
|
||||
sys_i32 game_player_dx = 0;
|
||||
sys_i32 game_player_dy = 0;
|
||||
|
||||
const char* game_title() {
|
||||
return "Croc Party!";
|
||||
}
|
||||
@ -23,6 +34,19 @@ void game_destroy() {
|
||||
|
||||
void game_update() {
|
||||
game_frame += 1;
|
||||
|
||||
game_player_dy += 1;
|
||||
|
||||
if (device_buttons[0]) { game_player_dx -= 16; }
|
||||
if (device_buttons[1]) { game_player_dx += 16; }
|
||||
|
||||
game_collision collision = game_collision_move_to_contact(
|
||||
&game_player_bbox,
|
||||
game_player_dx,
|
||||
game_player_dy
|
||||
);
|
||||
if (collision.collided_x) { game_player_dx = 0; }
|
||||
if (collision.collided_y) { game_player_dy = 0; }
|
||||
}
|
||||
|
||||
void game_draw() {
|
||||
@ -31,7 +55,10 @@ void game_draw() {
|
||||
sys_map_draw(map_game_map, spr_game_tiles, 0, 0, 0, 0, 32, 18);
|
||||
sys_sprite_draw_ext(
|
||||
spr_game_player,
|
||||
(game_frame / 8) % 4 * 2, 144, 88, 2, 2,
|
||||
(game_frame / 8) % 4 * 2,
|
||||
game_player_bbox.x / 0x100,
|
||||
game_player_bbox.y / 0x100,
|
||||
2, 2,
|
||||
false, false
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef CROCPARTY_GAME_H
|
||||
#define CROCPARTY_GAME_H
|
||||
|
||||
#include "game_collision.h"
|
||||
#include "game_palette.h"
|
||||
|
||||
const char* game_title();
|
||||
|
122
game/game_collision.c
Normal file
122
game/game_collision.c
Normal file
@ -0,0 +1,122 @@
|
||||
#include <assert.h>
|
||||
#include "sys/sys.h"
|
||||
#include "game.h"
|
||||
#include "map/game_map.h"
|
||||
|
||||
bool game_collision_is_occlusive(sys_maptile tile) {
|
||||
if (tile >= 0 && tile < 30) { return true; }
|
||||
if (tile >= 60 && tile < 90) { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
bool game_collision_can_move(game_bbox body, sys_i32 dx, sys_i32 dy) {
|
||||
sys_i32 x = body.x + dx;
|
||||
sys_i32 y = body.y + dy;
|
||||
|
||||
// the player can never leave the map
|
||||
if (x < 0) { return false; }
|
||||
if (y < 0) { return false; }
|
||||
if (x + body.w > map_game_map.width * TILE_SZ_MICROPIXEL) {
|
||||
return false;
|
||||
}
|
||||
if (y + body.h > map_game_map.height * TILE_SZ_MICROPIXEL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Collide with blocks
|
||||
// If two collides with a block, check if one collides with it.
|
||||
// The collision only matters if one doesn't.
|
||||
return true;
|
||||
}
|
||||
|
||||
#define round_down(x, incr) (x) - (x) % (incr)
|
||||
#define round_up(x, incr) round_down((x) + (incr) - 1, incr)
|
||||
|
||||
game_collision game_collision_move_to_contact(
|
||||
game_bbox* body, sys_i32 total_dx, sys_i32 total_dy
|
||||
) {
|
||||
sys_i32 src_x = body->x;
|
||||
sys_i32 src_y = body->y;
|
||||
game_collision collision = {
|
||||
.collided_x=false,
|
||||
.collided_y=false,
|
||||
.distance_x=0,
|
||||
.distance_y=0,
|
||||
};
|
||||
sys_i32 tar_x = body->x + total_dx;
|
||||
sys_i32 tar_y = body->y + total_dy;
|
||||
|
||||
while (true) {
|
||||
// calculate how much we still need to move
|
||||
int32_t remaining_dx = tar_x - body->x;
|
||||
int32_t remaining_dy = tar_y - body->y;
|
||||
|
||||
// if we don't need to move, stop
|
||||
if (remaining_dx == 0 && remaining_dy == 0) {
|
||||
collision.distance_x = body->x - src_x;
|
||||
collision.distance_y = body->x - src_y;
|
||||
return collision;
|
||||
}
|
||||
|
||||
// figure out where we are
|
||||
sys_i32 body_x0 = body->x;
|
||||
sys_i32 body_y0 = body->y;
|
||||
sys_i32 body_x1 = body->x + body->w;
|
||||
sys_i32 body_y1 = body->y + body->h;
|
||||
|
||||
// figure out what tile we're still in
|
||||
sys_i32 tile_x0 = round_down(body_x0, TILE_SZ_MICROPIXEL);
|
||||
sys_i32 tile_y0 = round_down(body_y0, TILE_SZ_MICROPIXEL);
|
||||
sys_i32 tile_x1 = round_up(body_x1, TILE_SZ_MICROPIXEL);
|
||||
sys_i32 tile_y1 = round_up(body_y1, TILE_SZ_MICROPIXEL);
|
||||
|
||||
// but we want the _next_ tile
|
||||
if (tile_x0 == body_x0) { tile_x0 -= TILE_SZ_MICROPIXEL; }
|
||||
if (tile_y0 == body_y0) { tile_y0 -= TILE_SZ_MICROPIXEL; }
|
||||
if (tile_x1 == body_x1) { tile_x1 += TILE_SZ_MICROPIXEL; }
|
||||
if (tile_y1 == body_y1) { tile_y1 += TILE_SZ_MICROPIXEL; }
|
||||
|
||||
// length of an x axis move
|
||||
int step_dx =
|
||||
remaining_dx < 0 ?
|
||||
// line up our left side with the tile to our left
|
||||
// not exceeding dx
|
||||
sys_max_i32(remaining_dx, tile_x0 - body_x0) :
|
||||
remaining_dx > 0 ?
|
||||
// line up our right side with the tile to our right
|
||||
// not exceeding dx
|
||||
sys_min_i32(remaining_dx, tile_x1 - body_x1) :
|
||||
// dx == 0
|
||||
INT32_MAX ;
|
||||
|
||||
int step_dy =
|
||||
remaining_dy < 0 ?
|
||||
// line up our top side with the tile above us
|
||||
// not exceeding dy
|
||||
sys_max_i32(remaining_dy, tile_y0 - body_y0) :
|
||||
remaining_dy > 0 ?
|
||||
// line up our bottom side with the tile below us
|
||||
// not exceeding dy
|
||||
sys_min_i32(remaining_dy, tile_y1 - body_y1) :
|
||||
INT32_MAX;
|
||||
|
||||
// there must be a viable move in some direction
|
||||
assert(step_dx != INT32_MAX || step_dy != INT32_MAX);
|
||||
|
||||
if (sys_abs_i32(step_dx) < sys_abs_i32(step_dy)) {
|
||||
if (game_collision_can_move(*body, step_dx, 0)) {
|
||||
body->x += step_dx; // take the tiny move
|
||||
} else {
|
||||
tar_x = body->x; // stop trying to move
|
||||
collision.collided_x = true;
|
||||
}
|
||||
} else {
|
||||
if (game_collision_can_move(*body, 0, step_dy)) {
|
||||
body->y += step_dy; // take the tiny move
|
||||
} else {
|
||||
tar_y = body->y; // stop trying to move
|
||||
collision.collided_y = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
27
game/game_collision.h
Normal file
27
game/game_collision.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef GAME_COLLISION_H
|
||||
#define GAME_COLLISION_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "sys/sys.h"
|
||||
|
||||
#define TILE_SZ_MICROPIXEL 0x800
|
||||
|
||||
typedef struct {
|
||||
sys_i32 x;
|
||||
sys_i32 y;
|
||||
sys_i32 w;
|
||||
sys_i32 h;
|
||||
} game_bbox;
|
||||
|
||||
typedef struct {
|
||||
bool collided_x;
|
||||
bool collided_y;
|
||||
sys_i32 distance_x;
|
||||
sys_i32 distance_y;
|
||||
} game_collision;
|
||||
|
||||
bool game_collision_is_occlusive(sys_maptile tile);
|
||||
bool game_collision_can_move(game_bbox body, sys_i32 dx, sys_i32 dy);
|
||||
game_collision game_collision_move_to_contact(game_bbox* body, sys_i32 x, sys_i32 y);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user