I don't even know what I did
This commit is contained in:
parent
fa23347b0d
commit
a46e0a4187
|
@ -45,6 +45,8 @@ if (DEFINED FXSDK_PLATFORM_LONG)
|
|||
# assets-cg/bg.png
|
||||
|
||||
assets-cg/bg.png
|
||||
assets-cg/bg_sunset.png
|
||||
assets-cg/skygarden_bg.png
|
||||
assets-cg/bush.png
|
||||
assets-cg/boost_0.png
|
||||
assets-cg/boost_1.png
|
||||
|
@ -107,12 +109,13 @@ if (DEFINED FXSDK_PLATFORM_LONG)
|
|||
assets-cg/smoke_0.png
|
||||
assets-cg/smoke_1.png
|
||||
assets-cg/smoke_2.png
|
||||
assets-cg/tree.png
|
||||
)
|
||||
|
||||
fxconv_declare_assets(${ASSETS} ${ASSETS_fx} ${ASSETS_cg} WITH_METADATA)
|
||||
|
||||
add_executable(mariokart ${SOURCES} ${ASSETS} ${ASSETS_${FXSDK_PLATFORM}})
|
||||
target_compile_options(mariokart PRIVATE -Wall -Wextra -Werror-implicit-function-declaration -Ofast -flto)
|
||||
target_compile_options(mariokart PRIVATE -Wall -Wextra -Werror-implicit-function-declaration -Ofast -flto -g)
|
||||
target_link_libraries(mariokart Gint::Gint)
|
||||
target_link_libraries(mariokart LibProf::LibProf)
|
||||
|
||||
|
@ -132,6 +135,6 @@ else()
|
|||
set(CMAKE_EXECUTABLE_SUFFIX ".html")
|
||||
add_executable(mariokart ${SOURCES})
|
||||
# -fsanitize=undefined on both
|
||||
target_compile_options(mariokart PRIVATE -Wall -Wextra -Werror=implicit-function-declaration -Werror=incompatible-pointer-types -g)
|
||||
target_compile_options(mariokart PRIVATE -Wall -Wextra -Werror=implicit-function-declaration -Werror=incompatible-pointer-types -O3 -g)
|
||||
target_link_options(mariokart PRIVATE --shell-file=../emscripten.html -g)
|
||||
endif()
|
||||
|
|
|
@ -249,3 +249,13 @@ bg_sunset.png:
|
|||
bg.png:
|
||||
type: bopti-image
|
||||
name: b_bg
|
||||
skygarden_bg.png:
|
||||
type: bopti-image
|
||||
name: b_skygarden_bg
|
||||
skygarden_bg2.png:
|
||||
type: bopti-image
|
||||
name: b_skygarden_bg2
|
||||
tree.png:
|
||||
type: bopti-image
|
||||
name: b_tree
|
||||
profile: rgb565a
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -209,3 +209,12 @@ const struct image* img_bg_sunset = &internal_img_bg_sunset;
|
|||
extern const bopti_image_t b_bg;
|
||||
const struct image internal_img_bg = { 0, 0, &b_bg };
|
||||
const struct image* img_bg = &internal_img_bg;
|
||||
extern const bopti_image_t b_skygarden_bg;
|
||||
const struct image internal_img_skygarden_bg = { 0, 0, &b_skygarden_bg };
|
||||
const struct image* img_skygarden_bg = &internal_img_skygarden_bg;
|
||||
extern const bopti_image_t b_skygarden_bg2;
|
||||
const struct image internal_img_skygarden_bg2 = { 0, 0, &b_skygarden_bg2 };
|
||||
const struct image* img_skygarden_bg2 = &internal_img_skygarden_bg2;
|
||||
extern const bopti_image_t b_tree;
|
||||
const struct image internal_img_tree = { 0, 0, &b_tree };
|
||||
const struct image* img_tree = &internal_img_tree;
|
||||
|
|
|
@ -72,3 +72,6 @@ extern const struct image* img_loop_old;
|
|||
extern const struct image* img_loop;
|
||||
extern const struct image* img_bg_sunset;
|
||||
extern const struct image* img_bg;
|
||||
extern const struct image* img_skygarden_bg;
|
||||
extern const struct image* img_skygarden_bg2;
|
||||
extern const struct image* img_tree;
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -72,3 +72,6 @@ extern const struct image* img_loop_old;
|
|||
extern const struct image* img_loop;
|
||||
extern const struct image* img_bg_sunset;
|
||||
extern const struct image* img_bg;
|
||||
extern const struct image* img_skygarden_bg;
|
||||
extern const struct image* img_skygarden_bg2;
|
||||
extern const struct image* img_tree;
|
||||
|
|
175
src/3d.c
175
src/3d.c
|
@ -5,7 +5,12 @@
|
|||
#include "./tilemap.h"
|
||||
#include "./maths.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "../data-headers/generated_lut.h"
|
||||
#include "platforms/gint.h"
|
||||
// #include "./3d-bg-dat.h"
|
||||
|
||||
#define lowResCutoff (LCD_HEIGHT_PX * 3 / 4) - 30
|
||||
|
||||
|
@ -22,8 +27,6 @@ void normalFov() {
|
|||
int dist = newLut[y - horizon];
|
||||
int wx = -(LCD_WIDTH_PX / 2) / 2 * dist;
|
||||
for (unsigned short x = 0; x < LCD_WIDTH_PX / 2; x++) {
|
||||
wx += dist;
|
||||
|
||||
int x2 = wx >> 6;
|
||||
int y2 = dist;
|
||||
|
||||
|
@ -32,10 +35,16 @@ void normalFov() {
|
|||
int newY = ((y2 * angleCos) >> 15) - ((x2 * angleSin) >> 15);
|
||||
|
||||
color_t col = samplePixel(newX >> 1, newY >> 1);
|
||||
// if (col == 0) {
|
||||
// color_t* img_data = (color_t*) data_3d_bg + 4;
|
||||
// col = img_data[(LCD_WIDTH_PX * (y - (horizon + 2))) + (x << 1)];
|
||||
// }
|
||||
// setPixel(x * 2, y, col);
|
||||
// setPixel(x * 2 + 1, y, col);
|
||||
// Cast to an unsigned int array so two pixels are stored at once.
|
||||
((unsigned int *)VRAM)[y * (LCD_WIDTH_PX / 2) + x] = (col << 16 | col);
|
||||
|
||||
wx += dist;
|
||||
}
|
||||
}
|
||||
// Fill in the low resolution area at half vertical resolution.
|
||||
|
@ -44,8 +53,6 @@ void normalFov() {
|
|||
int dist = newLut[y - horizon];
|
||||
int wx = -(LCD_WIDTH_PX / 2) / 2 * dist;
|
||||
for (unsigned short x = 0; x < LCD_WIDTH_PX / 2; x++) {
|
||||
wx += dist;
|
||||
|
||||
int x2 = wx >> 6;
|
||||
int y2 = dist;
|
||||
|
||||
|
@ -54,15 +61,150 @@ void normalFov() {
|
|||
int newY = ((y2 * angleCos) >> 15) - ((x2 * angleSin) >> 15);
|
||||
|
||||
color_t col = samplePixel(newX >> 1, newY >> 1);
|
||||
// if (col == 0) {
|
||||
// color_t* img_data = (color_t*) data_3d_bg + 4;
|
||||
// col = img_data[(LCD_WIDTH_PX * (y - (horizon + 2))) + (x << 1)];
|
||||
// }
|
||||
// setPixel(x * 2, y, col);
|
||||
// setPixel(x * 2 + 1, y, col);
|
||||
// Cast to an unsigned int array so two pixels are stored at once.
|
||||
((unsigned int *)VRAM)[y * (LCD_WIDTH_PX / 2) + x] = (col << 16 | col);
|
||||
((unsigned int *)VRAM)[(y + 1) * (LCD_WIDTH_PX / 2) + x] = (col << 16 | col);
|
||||
|
||||
wx += dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// void normalFov() {
|
||||
// for (unsigned short y = horizon + 2; y < LCD_HEIGHT_PX; y++) {
|
||||
// for (unsigned short x = 0; x < LCD_WIDTH_PX / 2; x++) {
|
||||
// int wx;
|
||||
// int wy;
|
||||
// screenToWorldSpace(x, y, &wx, &wy);
|
||||
// color_t col = samplePixel(wx, wy);
|
||||
// ((unsigned int *)VRAM)[y * (LCD_WIDTH_PX / 2) + x] = (col << 16 | col);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
void screenToWorldSpace(int x, int y, int* worldX, int* worldY) {
|
||||
int angleCos = fpcos(angle);
|
||||
int angleSin = fpsin(angle);
|
||||
|
||||
x /= 2;
|
||||
|
||||
int dist = newLut[y - horizon];
|
||||
int wx = -(LCD_WIDTH_PX / 2) / 2 * dist;
|
||||
wx += dist * x;
|
||||
|
||||
int x2 = wx >> 6;
|
||||
int y2 = dist;
|
||||
|
||||
// Rotate by angle
|
||||
int newX = ((x2 * angleCos) >> 15) + ((y2 * angleSin) >> 15);
|
||||
int newY = ((y2 * angleCos) >> 15) - ((x2 * angleSin) >> 15);
|
||||
|
||||
*worldX = newX >> 1;
|
||||
*worldY = newY >> 1;
|
||||
*worldX += xOffset;
|
||||
*worldY += yOffset;
|
||||
*worldX >>= 2;
|
||||
*worldY >>= 2;
|
||||
}
|
||||
|
||||
#define abs(x) ((x) < 0 ? -(x) : (x))
|
||||
|
||||
// void worldToScreenSpace(int worldX, int worldY, int* x, int* y) {
|
||||
// // RIDICULOUSLY inefficient way of doing this for testing purposes:
|
||||
// // Loop through all the pixels on the screen and find the one that
|
||||
// // is closest to the world coordinates.
|
||||
// int minDist = INT_MAX;
|
||||
// for (int i = 0; i < LCD_WIDTH_PX; i++) {
|
||||
// for (int j = horizon + 2; j < LCD_HEIGHT_PX; j++) {
|
||||
// int wx;
|
||||
// int wy;
|
||||
// screenToWorldSpace(i, j, &wx, &wy);
|
||||
// int dist = abs(worldX - wx) + abs(worldY - wy);
|
||||
// if (dist < minDist) {
|
||||
// minDist = dist;
|
||||
// *x = i;
|
||||
// *y = j;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// printf("minDist: %d\n", minDist);
|
||||
// }
|
||||
|
||||
// TODO: Take FOV into account
|
||||
void worldToScreenSpace(int worldX, int worldY, int* x, int* y, int* dist) {
|
||||
worldX <<= 2;
|
||||
worldY <<= 2;
|
||||
worldX -= xOffset;
|
||||
worldY -= yOffset;
|
||||
worldX <<= 1;
|
||||
worldY <<= 1;
|
||||
// Undo the rotation
|
||||
int angleCos = fpcos(-angle);
|
||||
int angleSin = fpsin(-angle);
|
||||
|
||||
int x2 = ((worldX * angleCos) >> 15) + ((worldY * angleSin) >> 15);
|
||||
int y2 = ((worldY * angleCos) >> 15) - ((worldX * angleSin) >> 15);
|
||||
|
||||
// Find the closest distance in the lookup table
|
||||
int minDist = INT_MAX;
|
||||
int minDistIndex = 0;
|
||||
for (int i = 0; i < LCD_HEIGHT_PX - horizon - 2; i++) {
|
||||
int dist = abs(newLut[i] - y2);
|
||||
if (dist < minDist) {
|
||||
minDist = dist;
|
||||
minDistIndex = i;
|
||||
}
|
||||
}
|
||||
*y = minDistIndex + horizon;
|
||||
// int dist2 = newLut[minDistIndex];
|
||||
int dist2 = y2;
|
||||
*dist = dist2;
|
||||
// *x = LCD_WIDTH_PX / 2;
|
||||
minDist = INT_MAX;
|
||||
minDistIndex = 0;
|
||||
// Find the closest x value
|
||||
// int wx = -(LCD_WIDTH_PX / 2) / 2 * dist2;
|
||||
// for (int i = 0; i < LCD_WIDTH_PX / 2; i++) {
|
||||
// int dist = abs((wx >> 6) - x2);
|
||||
// if (dist < minDist) {
|
||||
// minDist = dist;
|
||||
// minDistIndex = i;
|
||||
// }
|
||||
// wx += dist2;
|
||||
// }
|
||||
// Better way to do it:
|
||||
int wx = -(LCD_WIDTH_PX / 2) / 2 * dist2;
|
||||
// We are asking how many dist2s you need to wx add to get to x2 from wx
|
||||
// So just directly calculate that instead of doing the loop
|
||||
if ((dist2 >> 1) == 0) {
|
||||
*x = INT_MAX;
|
||||
return;
|
||||
}
|
||||
// int numDist2s = (x2 - (wx >> 6)) / (dist2 >> 6);
|
||||
// Do the division before the shift for increased precision
|
||||
// int numDist2s = ((x2 << 6) - wx) / (dist2 >> 6);
|
||||
// numDist2s >>= 6;
|
||||
|
||||
|
||||
|
||||
// int numDist2s = ((x2 << 6) - wx) / dist2;
|
||||
// minDistIndex = numDist2s /*- 1*/;
|
||||
|
||||
// *x = minDistIndex * 2;
|
||||
|
||||
// TODO: Division is slow on the SH4 CPU as there's no hardware divider
|
||||
// Can this be optimized? Or is the division just necessary?
|
||||
// Or is this done infrequently enough that it doesn't matter?
|
||||
*x = ((x2 << 6) - wx) / (dist2 >> 1);
|
||||
printf("x: %d\n", *x);
|
||||
}
|
||||
|
||||
void fullRes() {
|
||||
int angleCos = fpcos(angle);
|
||||
int angleSin = fpsin(angle);
|
||||
|
@ -70,8 +212,6 @@ void fullRes() {
|
|||
int dist = newLut[y - horizon];
|
||||
int wx = -(LCD_WIDTH_PX / 2) / 2 * dist;
|
||||
for (unsigned short x = 0; x < LCD_WIDTH_PX / 2; x++) {
|
||||
wx += dist;
|
||||
|
||||
int x2 = wx >> 6;
|
||||
int y2 = dist;
|
||||
|
||||
|
@ -80,10 +220,16 @@ void fullRes() {
|
|||
int newY = ((y2 * angleCos) >> 15) - ((x2 * angleSin) >> 15);
|
||||
|
||||
color_t col = samplePixel(newX >> 1, newY >> 1);
|
||||
// if (col == 0) {
|
||||
// color_t* img_data = (color_t*) data_3d_bg + 4;
|
||||
// col = img_data[(LCD_WIDTH_PX * (y - (horizon + 2))) + (x << 1)];
|
||||
// }
|
||||
// setPixel(x * 2, y, col);
|
||||
// setPixel(x * 2 + 1, y, col);
|
||||
// Cast to an unsigned int array so two pixels are stored at once.
|
||||
((unsigned int *)VRAM)[y * (LCD_WIDTH_PX / 2) + x] = (col << 16 | col);
|
||||
|
||||
wx += dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -97,8 +243,6 @@ void changedFov() {
|
|||
int wx = -(LCD_WIDTH_PX / 2) / 2;
|
||||
wx *= dx;
|
||||
for (unsigned short x = 0; x < LCD_WIDTH_PX / 2; x++) {
|
||||
wx += dx;
|
||||
|
||||
int x2 = wx >> 6;
|
||||
int y2 = dist;
|
||||
|
||||
|
@ -107,10 +251,15 @@ void changedFov() {
|
|||
int newY = ((y2 * angleCos) >> 15) - ((x2 * angleSin) >> 15);
|
||||
|
||||
color_t col = samplePixel(newX >> 1, newY >> 1);
|
||||
// setPixel(x * 2, y, col);
|
||||
// if (col == 0) {
|
||||
// color_t* img_data = (color_t*) data_3d_bg + 4;
|
||||
// col = img_data[(LCD_WIDTH_PX * (y - (horizon + 2))) + (x << 1)];
|
||||
// } // setPixel(x * 2, y, col);
|
||||
// setPixel(x * 2 + 1, y, col);
|
||||
// Cast to an unsigned int array so two pixels are stored at once.
|
||||
((unsigned int *)VRAM)[y * (LCD_WIDTH_PX / 2) + x] = (col << 16 | col);
|
||||
|
||||
wx += dx;
|
||||
}
|
||||
}
|
||||
// Fill in the low resolution area at half vertical resolution.
|
||||
|
@ -121,8 +270,6 @@ void changedFov() {
|
|||
int wx = -(LCD_WIDTH_PX / 2) / 2;
|
||||
wx *= dx;
|
||||
for (unsigned short x = 0; x < LCD_WIDTH_PX / 2; x++) {
|
||||
wx += dx;
|
||||
|
||||
int x2 = wx >> 6;
|
||||
int y2 = dist;
|
||||
|
||||
|
@ -131,11 +278,17 @@ void changedFov() {
|
|||
int newY = ((y2 * angleCos) >> 15) - ((x2 * angleSin) >> 15);
|
||||
|
||||
color_t col = samplePixel(newX >> 1, newY >> 1);
|
||||
// if (col == 0) {
|
||||
// color_t* img_data = (color_t*) data_3d_bg + 4;
|
||||
// col = img_data[(LCD_WIDTH_PX * (y - (horizon + 2))) + (x << 1)];
|
||||
// }
|
||||
// setPixel(x * 2, y, col);
|
||||
// setPixel(x * 2 + 1, y, col);
|
||||
// Cast to an unsigned int array so two pixels are stored at once.
|
||||
((unsigned int *)VRAM)[y * (LCD_WIDTH_PX / 2) + x] = (col << 16 | col);
|
||||
((unsigned int *)VRAM)[(y + 1) * (LCD_WIDTH_PX / 2) + x] = (col << 16 | col);
|
||||
|
||||
wx += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
2
src/3d.h
2
src/3d.h
|
@ -4,6 +4,8 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
unsigned short getScreenPixel(unsigned short x, unsigned short y);
|
||||
void screenToWorldSpace(int x, int y, int* worldX, int* worldY);
|
||||
void worldToScreenSpace(int worldX, int worldY, int* x, int* y, int* dist);
|
||||
void draw3D(bool highQuality);
|
||||
extern int hFovModifier;
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ EM_JS(void, initSliders, (), {
|
|||
max: 1,
|
||||
step: 0.01,
|
||||
value: 0.1,
|
||||
description: "A multiplier that is applied to the velocity every frame. This also affects the top speed, so if you adjust this, you'll probably want to adjust maxPower unless this is intended (as in the case of being off road)."
|
||||
description: "A multiplier that is applied to the velocity every frame. The value multiplied by is one minus this value. This also affects the top speed, so if you adjust this, you'll probably want to adjust maxPower unless this is intended (as in the case of being off road)."
|
||||
},
|
||||
{
|
||||
name: "offRoadDrag",
|
||||
|
@ -51,14 +51,14 @@ EM_JS(void, initSliders, (), {
|
|||
min: 0,
|
||||
max: 1,
|
||||
step: 0.01,
|
||||
value: 0.9,
|
||||
description: "A multiplier that is applied to the angular velocity every frame. Turning this up makes turning feel more slippery, as you will continue to turn for a bit after you stop pressing a direction."
|
||||
value: 0.1,
|
||||
description: "A multiplier that is applied to the angular velocity every frame. The value multiplied by is one minus this value. Turning this up makes turning feel more slippery, as you will continue to turn for a bit after you stop pressing a direction."
|
||||
},
|
||||
{
|
||||
name: "maxPower",
|
||||
min: 0,
|
||||
max: 0.5,
|
||||
step: 0.0001,
|
||||
step: 0.01,
|
||||
value: 0.1,
|
||||
description: "The maximum acceleration that can be applied to the kart - this is the main way of changing the top speed, along with drag."
|
||||
},
|
||||
|
@ -175,7 +175,7 @@ void updateConstants() {
|
|||
offRoadDrag = 1.0 - EM_ASM_DOUBLE({
|
||||
return window.constantValues.offRoadDrag;
|
||||
});
|
||||
angularDrag = EM_ASM_DOUBLE({
|
||||
angularDrag = 1.0 - EM_ASM_DOUBLE({
|
||||
return window.constantValues.angularDrag;
|
||||
});
|
||||
maxPower = EM_ASM_DOUBLE({
|
||||
|
|
22
src/data.c
22
src/data.c
|
@ -3,9 +3,11 @@
|
|||
|
||||
// #include "../data-headers/compressedTrack.h"
|
||||
#include "../data-headers/track.h"
|
||||
#include "../data-headers/images.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// extern unsigned char* compressedTrack;
|
||||
// extern int compressedTrackSize;
|
||||
|
@ -35,6 +37,9 @@ trackData tracks[] = {
|
|||
.tileTypes = peach_circuit_tileattr,
|
||||
.startX = 3565,
|
||||
.startY = 2600,
|
||||
.bg = 0,
|
||||
.fullBg = false,
|
||||
.drawLoop = true,
|
||||
},
|
||||
// Sunset Wilds
|
||||
{
|
||||
|
@ -48,6 +53,9 @@ trackData tracks[] = {
|
|||
.tileTypes = sunset_wilds_tileattr,
|
||||
.startX = 7425,
|
||||
.startY = 3673,
|
||||
.bg = 0,
|
||||
.fullBg = false,
|
||||
.drawLoop = false,
|
||||
},
|
||||
// Sky Garden
|
||||
{
|
||||
|
@ -61,6 +69,9 @@ trackData tracks[] = {
|
|||
.tileTypes = sky_garden_tileattr,
|
||||
.startX = 7060,
|
||||
.startY = 2900,
|
||||
.bg = 0,
|
||||
.fullBg = true,
|
||||
.drawLoop = false,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -70,6 +81,17 @@ void initData(int trackID) {
|
|||
// uncompress(trackData, &trackDataSize, compressedTrack, compressedTrackSize);
|
||||
|
||||
track = tracks[trackID];
|
||||
switch (trackID) {
|
||||
case 0:
|
||||
track.bg = img_bg;
|
||||
break;
|
||||
case 1:
|
||||
track.bg = img_bg_sunset;
|
||||
break;
|
||||
case 2:
|
||||
track.bg = img_skygarden_bg;
|
||||
break;
|
||||
}
|
||||
|
||||
mz_ulong size;
|
||||
|
||||
|
|
16
src/data.h
16
src/data.h
|
@ -3,21 +3,29 @@
|
|||
|
||||
#include "./platform.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
// https://github.com/thomasgoldstein/epicedit/blob/0a48fc/EpicEdit/Rom/Tracks/Road/RoadTileGenre.cs
|
||||
enum TileType {
|
||||
JumpBar = 0x10,
|
||||
// Edge of Choco Island road bump
|
||||
BumpEdge = 0x12,
|
||||
ItemBlock = 0x14,
|
||||
Zipper = 0x16,
|
||||
BoostPad = 0x16,
|
||||
OilSlick = 0x18,
|
||||
Coin = 0x1A,
|
||||
// Choco Island road bump
|
||||
Bump = 0x1C,
|
||||
WoodPlank = 0x1E,
|
||||
// Air where you fall off the road (e.g. on Rainbow Road)
|
||||
Empty = 0x20,
|
||||
Water = 0x22,
|
||||
Lava = 0x24,
|
||||
OutOfBounds = 0x26,
|
||||
// Empty border that delimits the road and the void, on Rainbow Road
|
||||
EmptyBorder = 0x28,
|
||||
Road = 0x40,
|
||||
// Ghost Valley plank intersection
|
||||
PlankJunction = 0x42,
|
||||
BrickRoad = 0x44,
|
||||
Clay = 0x46,
|
||||
|
@ -33,8 +41,11 @@ enum TileType {
|
|||
Grass = 0x5A,
|
||||
ShallowWater = 0x5C,
|
||||
Mud = 0x5E,
|
||||
// Boundary that can't be driven through or jumped over
|
||||
SolidBlock = 0x80,
|
||||
// Breaks when hit
|
||||
FrailBlock = 0x82,
|
||||
// Also breaks when hit
|
||||
IceBlock = 0x84
|
||||
};
|
||||
|
||||
|
@ -50,6 +61,9 @@ typedef struct {
|
|||
int startX;
|
||||
int startY;
|
||||
// color_t skyColor;
|
||||
const struct image* bg;
|
||||
bool fullBg;
|
||||
bool drawLoop;
|
||||
} trackData;
|
||||
|
||||
extern trackData track;
|
||||
|
|
494
src/main.c
494
src/main.c
|
@ -13,13 +13,26 @@
|
|||
#include "./configurableConstants.h"
|
||||
|
||||
#include "../data-headers/images.h"
|
||||
#include "platforms/gint.h"
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#include "gint/display-cg.h"
|
||||
#include "gint/display.h"
|
||||
#include "gint/keyboard.h"
|
||||
#include "gint/keycodes.h"
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef PROFILING_ENABLED
|
||||
#include "libprof.h"
|
||||
#endif
|
||||
// TODO: remove
|
||||
// #include <math.h>
|
||||
double sqrt(double arg);
|
||||
|
||||
#include "./data.h"
|
||||
|
||||
// #ifdef PROFILING_ENABLED
|
||||
// #include "libprof.h"
|
||||
// #endif
|
||||
|
||||
#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
|
||||
#define MAX(X, Y) (((X) < (Y)) ? (Y) : (X))
|
||||
|
@ -91,7 +104,7 @@ void printTileType(enum TileType tileType) {
|
|||
case ItemBlock:
|
||||
printf("ItemBlock\n");
|
||||
break;
|
||||
case Zipper:
|
||||
case BoostPad:
|
||||
printf("Zipper\n");
|
||||
break;
|
||||
case OilSlick:
|
||||
|
@ -189,10 +202,6 @@ void printTileType(enum TileType tileType) {
|
|||
}
|
||||
#endif
|
||||
|
||||
enum TileType getTileType(int tileID) {
|
||||
return (enum TileType) track.tileTypes[tileID];
|
||||
}
|
||||
|
||||
short index2;
|
||||
unsigned short element;
|
||||
|
||||
|
@ -303,7 +312,9 @@ int timerFrames;
|
|||
int freezeForFrames = 0;
|
||||
int freezeTime;
|
||||
|
||||
bool didFinishLap = false;
|
||||
#define LAPS 3
|
||||
int lapTimes[LAPS];
|
||||
|
||||
bool hudUpdated = false;
|
||||
bool minutesUpdated = false;
|
||||
bool secondsUpdated = false;
|
||||
|
@ -311,9 +322,9 @@ bool millisecondsUpdated = false;
|
|||
bool wholeTimerUpdated = false;
|
||||
bool trackNeedsUpdate = true;
|
||||
|
||||
void drawTimer() {
|
||||
void drawTimer(bool didFinishLap) {
|
||||
// Calculate the total time in mm:ss:xx format
|
||||
if (state.player.lapCount <= 3) {
|
||||
if (state.player.lapCount <= LAPS) {
|
||||
timerFrames = state.totalFrameCount - 180;
|
||||
}
|
||||
// timerFrames *= 8;
|
||||
|
@ -323,6 +334,7 @@ void drawTimer() {
|
|||
if (didFinishLap && state.player.lapCount > 1) {
|
||||
freezeForFrames = 150;
|
||||
freezeTime = (state.totalFrameCount - 180) - lastLapTime;
|
||||
lapTimes[state.player.lapCount - 2] = freezeTime;
|
||||
lastLapTime = (state.totalFrameCount - 180);
|
||||
}
|
||||
|
||||
|
@ -369,10 +381,32 @@ void drawTimer() {
|
|||
|
||||
// Draw text
|
||||
draw_time(timeStr, LCD_WIDTH_PX - 90, 8);
|
||||
|
||||
static bool fullTimerDisplayed = false;
|
||||
// If the player finished all 3 laps and the timer isn't frozen
|
||||
// Only do it once, though
|
||||
if (state.player.lapCount >= (LAPS + 1) && freezeForFrames == 0 && !fullTimerDisplayed) {
|
||||
// Print the times for each lap below the timer
|
||||
for (int i = 0; i < LAPS; i++) {
|
||||
int lapTime = lapTimes[i];
|
||||
int lapMinutes = lapTime / 60 / 60;
|
||||
int lapSeconds = (lapTime / 60) % 60;
|
||||
int lapMilliseconds = ((lapTime % 60) * 16667) / 1000;
|
||||
if (lapMilliseconds >= 1000) {
|
||||
lapMilliseconds = 999;
|
||||
}
|
||||
char lapTimeStr[9];
|
||||
sprintf(lapTimeStr, "%02d:%02d:%02d", lapMinutes, lapSeconds, lapMilliseconds / 10);
|
||||
draw_time(lapTimeStr, LCD_WIDTH_PX - 90, 8 + (i + 2) * 12);
|
||||
displayUpdate(0, LCD_HEIGHT_PX - 1);
|
||||
}
|
||||
fullTimerDisplayed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawParallaxBackground(int angle) {
|
||||
if (!track.drawLoop) return;
|
||||
draw_loop_x(img_loop, 0, 88, angle / 2, LCD_WIDTH_PX);
|
||||
draw_loop_x(img_bush, 0, 100, angle, LCD_WIDTH_PX);
|
||||
}
|
||||
|
@ -385,11 +419,15 @@ void fillSky(unsigned short yMin, unsigned short yMax) {
|
|||
}
|
||||
} */
|
||||
// TODO: more efficient drawing?
|
||||
for (int x = 0; x < LCD_WIDTH_PX; x++) {
|
||||
draw(img_bg, x, 0);
|
||||
if (track.fullBg) {
|
||||
draw(track.bg, 0, 0);
|
||||
} else {
|
||||
for (int x = 0; x < LCD_WIDTH_PX; x++) {
|
||||
draw(track.bg, x, 0);
|
||||
}
|
||||
}
|
||||
drawLapCount();
|
||||
drawTimer();
|
||||
drawTimer(false);
|
||||
drawParallaxBackground(angle);
|
||||
// extern bopti_image_t img_bg;
|
||||
// dimage(0, 0, &img_bg);
|
||||
|
@ -404,13 +442,10 @@ void main_loop() {
|
|||
0xB882, 0xCBCE, 0xF6BA
|
||||
};
|
||||
palette[0x3C] = paletteAnim[(state.totalFrameCount / 3) % 3];
|
||||
// for (int i = 0; i < 256; i++) {
|
||||
// palette[i] = 0xFFFF;
|
||||
// }
|
||||
|
||||
updateConstants();
|
||||
|
||||
didFinishLap = false;
|
||||
bool didFinishLap = false;
|
||||
hudUpdated = false;
|
||||
minutesUpdated = false;
|
||||
secondsUpdated = false;
|
||||
|
@ -418,14 +453,6 @@ void main_loop() {
|
|||
wholeTimerUpdated = false;
|
||||
|
||||
// Main game loop
|
||||
#ifdef PROFILING_ENABLED
|
||||
prof_t prof_logic = prof_make();
|
||||
prof_t prof_logic1 = prof_make();
|
||||
prof_t prof_logic2 = prof_make();
|
||||
prof_t prof_logic3 = prof_make();
|
||||
prof_t prof_sprites = prof_make();
|
||||
prof_enter(prof_logic);
|
||||
#endif
|
||||
|
||||
scanButtons();
|
||||
|
||||
|
@ -441,144 +468,17 @@ void main_loop() {
|
|||
state = savedState;
|
||||
}
|
||||
|
||||
#ifdef PROFILING_ENABLED
|
||||
prof_leave(prof_logic);
|
||||
#endif
|
||||
|
||||
timeDebugHud = profile({
|
||||
handleDebugHud();
|
||||
});
|
||||
|
||||
#ifdef PROFILING_ENABLED
|
||||
prof_enter(prof_logic);
|
||||
#endif
|
||||
// printTileType(tileType);
|
||||
|
||||
// turnSpeed = state.player.drifting ? 0.003: 0.002;
|
||||
|
||||
unsigned char currentTile = getTileID(kartX / scale, kartY / scale);
|
||||
enum TileType tileType = getTileType(currentTile);
|
||||
printTileType(tileType);
|
||||
bool isOffRoad = tileType == Offroad || tileType == Grass || tileType == ShallowWater;
|
||||
if (tileType == Zipper) {
|
||||
state.player.boostTime = 100;
|
||||
addParticle(2, LCD_WIDTH_PX / 2 - 28, LCD_HEIGHT_PX - 70, 0, 0);
|
||||
}
|
||||
|
||||
if (state.player.drifting && !isOffRoad) {
|
||||
if ((buttons.left && state.player.driftDir == -1) || (buttons.right && state.player.driftDir == 1)) {
|
||||
state.player.driftCharge += 2;
|
||||
} else {
|
||||
state.player.driftCharge++;
|
||||
}
|
||||
} else {
|
||||
state.player.driftCharge = 0;
|
||||
/* for (int x = 0; x < LCD_WIDTH_PX / 2; x++) {
|
||||
for (int y = 0; y < 4; y++) {
|
||||
// setPixel(i, j, 0xF800);
|
||||
((unsigned int *)VRAM)[y * (LCD_WIDTH_PX / 2) + x] = (0x0CDF << 16) | 0x0CDF;
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
// if (state.player.driftCharge > 60) {
|
||||
// state.player.driftCharge = 60;
|
||||
// }
|
||||
|
||||
/* if (state.player.driftCharge > 0) {
|
||||
// Draw a 4px red bar at the top of the screen
|
||||
int barWidth = state.player.driftCharge * LCD_WIDTH_PX / 60 / 2;
|
||||
for (int x = 0; x < barWidth; x++) {
|
||||
for (int y = 0; y < 4; y++) {
|
||||
// setPixel(i, j, 0xF800);
|
||||
((unsigned int *)VRAM)[y * (LCD_WIDTH_PX / 2) + x] = (0xF800 << 16) | 0xF800;
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
#ifdef PROFILING_ENABLED
|
||||
prof_leave(prof_logic);
|
||||
prof_enter(prof_logic1);
|
||||
#endif
|
||||
|
||||
if (!buttons.hop) {
|
||||
if (state.player.drifting && state.player.driftCharge >= 60) {
|
||||
if (state.player.driftCharge > 360) {
|
||||
state.player.boostTime = 100;
|
||||
addParticle(2, LCD_WIDTH_PX / 2 - 28, LCD_HEIGHT_PX - 70, 0, 0);
|
||||
} else if (state.player.driftCharge >= 180) {
|
||||
state.player.boostTime = 50;
|
||||
addParticle(1, LCD_WIDTH_PX / 2 - 28, LCD_HEIGHT_PX - 70, 0, 0);
|
||||
} else {
|
||||
state.player.boostTime = 20;
|
||||
addParticle(3, LCD_WIDTH_PX / 2 - 28, LCD_HEIGHT_PX - 70, 0, 0);
|
||||
}
|
||||
}
|
||||
state.player.drifting = false;
|
||||
}
|
||||
|
||||
if (buttons.hop && !lastButtons.hop && state.player.hopStage == 0) {
|
||||
state.player.hopStage = 1;
|
||||
if (buttons.left || buttons.right) {
|
||||
state.player.drifting = true;
|
||||
state.player.driftDir = buttons.left ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (state.player.hopStage != 0) {
|
||||
state.player.hopStage++;
|
||||
if (state.player.hopStage >= 15) {
|
||||
state.player.hopStage = 0;
|
||||
if (!state.player.drifting && (buttons.left || buttons.right)) {
|
||||
state.player.drifting = true;
|
||||
state.player.driftDir = buttons.left ? -1 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if (state.player.drifting) {
|
||||
// debug_printf("state.player.driftDir: %d\n", state.player.driftDir);
|
||||
if (state.player.driftDir == 1) {
|
||||
buttons.right = true;
|
||||
buttons.left = false;
|
||||
} else {
|
||||
buttons.left = true;
|
||||
buttons.right = false;
|
||||
}
|
||||
} */
|
||||
|
||||
#ifdef PROFILING_ENABLED
|
||||
prof_leave(prof_logic1);
|
||||
prof_enter(prof_logic2);
|
||||
#endif
|
||||
|
||||
/* if (buttons.debug_boost) {
|
||||
state.player.boostTime = 30;
|
||||
addParticle(1, LCD_WIDTH_PX / 2 - 28, LCD_HEIGHT_PX - 70, 0, 0);
|
||||
} */
|
||||
|
||||
bool boosting = false;
|
||||
if (state.player.boostTime >= 0) {
|
||||
state.player.boostTime--;
|
||||
boosting = true;
|
||||
}
|
||||
|
||||
if (boosting) {
|
||||
// maxPower = 0.15;
|
||||
// powerFactor = 0.002;
|
||||
applyBoost = true;
|
||||
state.player.power = maxPower;
|
||||
buttons.accel = true;
|
||||
|
||||
// hFovModifier = (1 << 12) * 1.2;
|
||||
if (hFovModifier < (1 << 12) * 1.2) {
|
||||
hFovModifier += (1 << 12) * 0.05;
|
||||
}
|
||||
} else {
|
||||
// maxPower = 0.1;
|
||||
// powerFactor = 0.001;
|
||||
applyBoost = false;
|
||||
|
||||
// hFovModifier = 1 << 12;
|
||||
if (hFovModifier > 1 << 12) {
|
||||
hFovModifier -= (1 << 12) * 0.02;
|
||||
}
|
||||
|
@ -587,35 +487,16 @@ void main_loop() {
|
|||
}
|
||||
}
|
||||
|
||||
if (!boosting && isOffRoad) {
|
||||
applyOffRoadDrag = true;
|
||||
} else {
|
||||
applyOffRoadDrag = false;
|
||||
}
|
||||
|
||||
double oldKartY = state.player.y;
|
||||
double oldKartX = state.player.x;
|
||||
|
||||
#ifdef PROFILING_ENABLED
|
||||
prof_leave(prof_logic2);
|
||||
#endif
|
||||
|
||||
int lastLapCount = state.player.lapCount;
|
||||
timePhysics = profile({
|
||||
updateWithControls(&state.player, buttons);
|
||||
});
|
||||
|
||||
#ifdef PROFILING_ENABLED
|
||||
prof_enter(prof_logic2);
|
||||
#endif
|
||||
|
||||
unsigned char newTile = getTileID(state.player.x * 12 / scale, state.player.y * 12 / scale);
|
||||
if (getTileType(newTile) == SolidBlock) {
|
||||
state.player.x = oldKartX;
|
||||
state.player.y = oldKartY;
|
||||
if (state.player.lapCount > lastLapCount) {
|
||||
didFinishLap = true;
|
||||
}
|
||||
|
||||
kartX = state.player.x * 12;
|
||||
kartY = state.player.y * 12;
|
||||
kartX = state.player.x;
|
||||
kartY = state.player.y;
|
||||
|
||||
// Radians to degrees
|
||||
kartAngle = -state.player.angle * 180 / 3.1415926;
|
||||
|
@ -627,30 +508,6 @@ void main_loop() {
|
|||
kartAngle = fmod(kartAngle, 360);
|
||||
|
||||
angle = fmod(kartAngle + 90, 360) * angleWidth / 90;
|
||||
|
||||
/* for (unsigned short x = 0; x < LCD_WIDTH_PX / 2; x++) {
|
||||
index2 = x + angle;
|
||||
index2 = mod(index2, (angleWidth * 4));
|
||||
element = mod(index2, angleWidth);
|
||||
// TODO: Plus 2?
|
||||
for (unsigned short y = horizon + 2; y < LCD_HEIGHT_PX; y += 1) {
|
||||
unsigned short thing = getScreenPixel(x, y);
|
||||
setPixel(x * 2, y, thing);
|
||||
setPixel(x * 2 + 1, y, thing);
|
||||
}
|
||||
} */
|
||||
|
||||
if (newTile == 254 && currentTile != 254) {
|
||||
state.player.lapCount++;
|
||||
didFinishLap = true;
|
||||
#ifdef __EMSCRIPTEN__
|
||||
printf("Lap %d\n", state.player.lapCount);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PROFILING_ENABLED
|
||||
prof_leave(prof_logic2);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (abs_double(state.player.xVelocity) + abs_double(state.player.yVelocity) < 0.02) {
|
||||
|
@ -683,7 +540,6 @@ void main_loop() {
|
|||
if (state.player.driftDir == -1 && targetAnim < 7) {
|
||||
targetAnim = 7;
|
||||
}
|
||||
// debug_printf("state.player.driftDir: %d, targetAnim: %d\n", state.player.driftDir, targetAnim);
|
||||
}
|
||||
|
||||
if (state.player.kartSteerAnim != targetAnim) {
|
||||
|
@ -729,6 +585,7 @@ void main_loop() {
|
|||
|
||||
time3D = profile({
|
||||
static bool lastTrackNeedsUpdate = true;
|
||||
// fillSky(0, LCD_HEIGHT_PX);
|
||||
if (trackNeedsUpdate) {
|
||||
// Only use high quality during the countdown
|
||||
draw3D(state.totalFrameCount <= 240);
|
||||
|
@ -742,15 +599,11 @@ void main_loop() {
|
|||
trackNeedsUpdate = false;
|
||||
});
|
||||
|
||||
#ifdef PROFILING_ENABLED
|
||||
prof_enter(prof_logic3);
|
||||
#endif
|
||||
|
||||
// Draw parallax background if the angle has changed
|
||||
// TODO: Can we use the existing variable here?
|
||||
static int lastAngle2 = 99999;
|
||||
bool bgRedraw = false;
|
||||
if (lastAngle2 != angle) {
|
||||
if (lastAngle2 != angle && track.drawLoop) {
|
||||
bgRedraw = true;
|
||||
drawParallaxBackground(angle);
|
||||
lastAngle2 = angle;
|
||||
|
@ -780,10 +633,7 @@ void main_loop() {
|
|||
x -= v / 2;
|
||||
x += (state.totalFrameCount / 2) % 3 * sign;
|
||||
y += (state.totalFrameCount / 2) % 2;
|
||||
#ifdef PROFILING_ENABLED
|
||||
prof_leave(prof_logic3);
|
||||
prof_enter(prof_sprites);
|
||||
#endif
|
||||
|
||||
if (sign == 1) {
|
||||
draw(imgs_fire[fireStage], x, y);
|
||||
draw(imgs_fire[fireStage], x + (state.totalFrameCount / 2) % 2 * 3, y + 5);
|
||||
|
@ -791,15 +641,8 @@ void main_loop() {
|
|||
draw_flipped(imgs_fire[fireStage], x, y);
|
||||
draw_flipped(imgs_fire[fireStage], x - (state.totalFrameCount / 2) % 2 * 3, y + 5);
|
||||
}
|
||||
#ifdef PROFILING_ENABLED
|
||||
prof_leave(prof_sprites);
|
||||
prof_enter(prof_logic3);
|
||||
#endif
|
||||
}
|
||||
|
||||
// debug_printf("state.totalFrameCount: %d\n", state.totalFrameCount);
|
||||
|
||||
|
||||
if (state.player.drifting) {
|
||||
if (state.totalFrameCount % 8 == 0) {
|
||||
addParticle(0, 192 + -32 * state.player.driftDir, 180, -5 * state.player.driftDir, state.totalFrameCount % 16 == 0 ? -1 : 1);
|
||||
|
@ -808,26 +651,50 @@ void main_loop() {
|
|||
|
||||
int animNo = abs_int(state.player.kartSteerAnim) / 2;
|
||||
int newAnimNo = animNo + ((jitter / 2) * 11);
|
||||
// debug_printf("animNo: %d\n", animNo);
|
||||
|
||||
// draw_alpha(img_shadow, (LCD_WIDTH_PX / 2) - (96 / 2), 116, 2);
|
||||
// if (state.totalFrameCount % 2 == 0) {
|
||||
// draw(img_shadow1, (LCD_WIDTH_PX / 2) - (96 / 2), 112);
|
||||
// int y = LCD_HEIGHT_PX - 100;
|
||||
// int x = LCD_WIDTH_PX / 2;
|
||||
// VRAM[y * LCD_WIDTH_PX + x] = 0xF800;
|
||||
// int worldX;
|
||||
// int worldY;
|
||||
// screenToWorldSpace(x, y, &worldX, &worldY);
|
||||
|
||||
#define tileSize 8
|
||||
#define trackImageWidth 256 * tileSize
|
||||
#define trackImageHeight 256 * tileSize
|
||||
|
||||
// // Set the tile ID at worldX, worldY to 0
|
||||
// if (!(worldX < 0 || worldX >= trackImageWidth || worldY < 0 || worldY >= trackImageHeight)) {
|
||||
// int xPixel = worldX >> 3;
|
||||
// int yPixel = worldY >> 3;
|
||||
// int tileID = tilemap[((yPixel * (trackImageWidth / tileSize)) + xPixel)];
|
||||
// if (tileID != 0) {
|
||||
// printf("Setting: %d, %d\n", worldX, worldY);
|
||||
// tilemap[((yPixel * (trackImageWidth / tileSize)) + xPixel)] = 0;
|
||||
// trackNeedsUpdate = true;
|
||||
// } else {
|
||||
// printf("Tile already 0\n");
|
||||
// }
|
||||
// } else {
|
||||
// draw(img_shadow2, (LCD_WIDTH_PX / 2) - (96 / 2), 112);
|
||||
// printf("Out of bounds: %d, %d\n", worldX, worldY);
|
||||
// }
|
||||
|
||||
tilemap[(((239 >> 3) * (trackImageWidth / tileSize)) + (888 >> 3))] = 0;
|
||||
|
||||
|
||||
// for (int i = -1; i <= 1; i++) {
|
||||
// for (int j = -1; j <= 1; j++) {
|
||||
// if ((y + i) >= 0 && (y + i) < LCD_HEIGHT_PX && (x + j) >= 0 && (x + j) < LCD_WIDTH_PX) {
|
||||
// VRAM[(y + i) * LCD_WIDTH_PX + (x + j)] = 0xF800;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#ifdef PROFILING_ENABLED
|
||||
prof_leave(prof_logic3);
|
||||
#endif
|
||||
|
||||
timeKartSprite = profile({
|
||||
if (state.player.hopStage != 0) {
|
||||
draw(img_shadow1, (LCD_WIDTH_PX / 2) - (96 / 2), 112);
|
||||
}
|
||||
if (state.player.kartSteerAnim >= 0) {
|
||||
// CopySpriteMasked(/*mksprites[state.player.kartSteerAnim / 2]*/sprite, (LCD_WIDTH_PX / 2) - 39, 128, 78, 81, 0x07e0);
|
||||
// CopySpriteMasked(mksprites[state.player.kartSteerAnim / 4], (LCD_WIDTH_PX / 2) - 36, 128, 72, 80, 0x4fe0);
|
||||
if (newAnimNo == animNo) {
|
||||
draw(imgs_kart[animNo], (LCD_WIDTH_PX / 2) - (96 / 2), horizon + 4 + (jitter % 2) - (hopAnim[state.player.hopStage] * 3));
|
||||
} else {
|
||||
|
@ -835,8 +702,6 @@ void main_loop() {
|
|||
draw(imgs_kart[newAnimNo], (LCD_WIDTH_PX / 2) - (96 / 2), horizon + 4 + (jitter % 2) - (hopAnim[state.player.hopStage] * 3));
|
||||
}
|
||||
} else {
|
||||
// CopySpriteMaskedFlipped(/*mksprites[-state.player.kartSteerAnim / 2]*/sprite, (LCD_WIDTH_PX / 2) - 39, 128, 78, 81, 0x07e0);
|
||||
// CopySpriteMaskedFlipped(mksprites[-state.player.kartSteerAnim / 4], (LCD_WIDTH_PX / 2) - 36, 128, 72, 80, 0x4fe0);
|
||||
if (newAnimNo == animNo) {
|
||||
draw_flipped(imgs_kart[animNo], (LCD_WIDTH_PX / 2) - (96 / 2), horizon + 4 + (jitter % 2) - (hopAnim[state.player.hopStage] * 3));
|
||||
} else {
|
||||
|
@ -844,22 +709,13 @@ void main_loop() {
|
|||
draw_flipped(imgs_kart[newAnimNo], (LCD_WIDTH_PX / 2) - (96 / 2) - (state.player.kartSteerAnim == -20 ? 1 : 0), horizon + 4 + (jitter % 2) - (hopAnim[state.player.hopStage] * 3));
|
||||
}
|
||||
}
|
||||
// draw_scaled(imgs_kart[animNo], (LCD_WIDTH_PX / 2) - (96 / 2), horizon + 4 + (jitter % 2) - (hopAnim[state.player.hopStage] * 3) + 30, (1 / 1.5), (1 / 1.5));
|
||||
});
|
||||
|
||||
#ifdef PROFILING_ENABLED
|
||||
prof_enter(prof_sprites);
|
||||
#endif
|
||||
|
||||
// TODO: Don't profile all of it as sprites?
|
||||
bool particlesUpdated = tickParticles();
|
||||
// TODO: Make this happen before the 3D is drawn
|
||||
trackNeedsUpdate = trackNeedsUpdate || particlesUpdated;
|
||||
|
||||
// Bdisp_PutDisp_DD_stripe(horizon + 2, LCD_HEIGHT_PX);
|
||||
// dupdate();
|
||||
|
||||
// const int fontWidths[] = {10, 5, 10, 9, 11, };
|
||||
|
||||
#define skyColor 0x0CDF
|
||||
// #define skyColor 0xD80C
|
||||
if (debugType <= 1) {
|
||||
|
@ -870,10 +726,6 @@ void main_loop() {
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifdef PROFILING_ENABLED
|
||||
prof_leave(prof_sprites);
|
||||
prof_enter(prof_logic3);
|
||||
#endif
|
||||
|
||||
if (state.totalFrameCount < 240) {
|
||||
int stage = state.totalFrameCount / 60;
|
||||
|
@ -881,7 +733,8 @@ void main_loop() {
|
|||
if (stage != lastStage) {
|
||||
fillSky(0, horizon);
|
||||
}
|
||||
draw(imgs_countdown[3 - stage], offX(-152 / 2), offY(-66 / 2));
|
||||
// draw(imgs_countdown[3 - stage], offX(-152 / 2), offY(-66 / 2));
|
||||
// draw_scaled(imgs_countdown[3 - stage], offX(-152 / 2), offY(-66 / 2), 0.5, 0.5);
|
||||
if (stage != lastStage) {
|
||||
displayUpdate(0, horizon + 2);
|
||||
}
|
||||
|
@ -896,12 +749,7 @@ void main_loop() {
|
|||
displayUpdate(0, horizon + 2);
|
||||
}
|
||||
|
||||
#ifdef PROFILING_ENABLED
|
||||
prof_leave(prof_logic3);
|
||||
prof_enter(prof_sprites);
|
||||
#endif
|
||||
|
||||
drawTimer();
|
||||
drawTimer(didFinishLap);
|
||||
|
||||
// Lap count
|
||||
static int lastLap = -1;
|
||||
|
@ -912,64 +760,66 @@ void main_loop() {
|
|||
lastLap = lap;
|
||||
}
|
||||
|
||||
#ifdef PROFILING_ENABLED
|
||||
prof_leave(prof_sprites);
|
||||
prof_enter(prof_logic3);
|
||||
#endif
|
||||
// Draw a sprite at 888, 239 in world space
|
||||
// First calculate the distance from the camera
|
||||
// int dx = 888 - (xOffset >> 2);
|
||||
// int dy = 239 - (yOffset >> 2);
|
||||
// float dist = sqrt(dx * dx + dy * dy);
|
||||
// printf("Dist: %f\n", dist);
|
||||
int x;
|
||||
int y;
|
||||
int dist;
|
||||
worldToScreenSpace(888, 239, &x, &y, &dist);
|
||||
printf("Dist: %d\n", dist);
|
||||
const float size = 200;
|
||||
if (dist >= 1 && (y - (64 * size / dist) > (LCD_HEIGHT_PX / 2) - 2)) {
|
||||
VRAM[y * LCD_WIDTH_PX + x] = 0xF800;
|
||||
draw_scaled(img_tree, x - (28 * size / dist), y - (64 * size / dist), size / dist, size / dist);
|
||||
}
|
||||
|
||||
#ifdef PROFILING_ENABLED
|
||||
prof_leave(prof_logic3);
|
||||
timeLogic = prof_time(prof_logic);
|
||||
timeLogic2 = prof_time(prof_logic2);
|
||||
timeLogic3 = prof_time(prof_logic3);
|
||||
timeSprites = prof_time(prof_sprites);
|
||||
#endif
|
||||
|
||||
timeUpdate = profile({
|
||||
// draw(img_loop, angle, 92);
|
||||
if (bgRedraw) {
|
||||
displayUpdate(88, 92);
|
||||
displayUpdate(100, 108);
|
||||
}
|
||||
// draw(img_loop, angle, 92);
|
||||
if (bgRedraw) {
|
||||
displayUpdate(88, 92);
|
||||
displayUpdate(100, 108);
|
||||
}
|
||||
|
||||
// if (state.totalFrameCount % 2 == 0) {
|
||||
// Update timer on screen
|
||||
// if (state.totalFrameCount % 2 == 0) {
|
||||
// Update timer on screen
|
||||
|
||||
// Update HUD
|
||||
if (hudUpdated) {
|
||||
displayUpdate(8, 24);
|
||||
} else if (wholeTimerUpdated) {
|
||||
displayUpdateBox(306, 8, 81, 12);
|
||||
} else {
|
||||
if (minutesUpdated) {
|
||||
displayUpdateBox(306, 8, 24, 12);
|
||||
}
|
||||
if (secondsUpdated) {
|
||||
displayUpdateBox(336, 8, 24, 12);
|
||||
}
|
||||
if (millisecondsUpdated) {
|
||||
displayUpdateBox(365, 8, 24, 12);
|
||||
}
|
||||
// Update HUD
|
||||
if (hudUpdated) {
|
||||
displayUpdate(8, 24);
|
||||
} else if (wholeTimerUpdated) {
|
||||
displayUpdateBox(306, 8, 81, 12);
|
||||
} else {
|
||||
if (minutesUpdated) {
|
||||
displayUpdateBox(306, 8, 24, 12);
|
||||
}
|
||||
if (secondsUpdated) {
|
||||
displayUpdateBox(336, 8, 24, 12);
|
||||
}
|
||||
if (millisecondsUpdated) {
|
||||
displayUpdateBox(365, 8, 24, 12);
|
||||
}
|
||||
}
|
||||
|
||||
// Update track on screen
|
||||
if (trackDisplayUpdateNeeded) {
|
||||
displayUpdate(horizon + 2, LCD_HEIGHT_PX);
|
||||
}
|
||||
// }
|
||||
// Update track on screen
|
||||
#ifdef PROFILING_ENABLED
|
||||
// This means you don't need to be moving to get accurate profiling data
|
||||
trackDisplayUpdateNeeded = true;
|
||||
#endif
|
||||
if (trackDisplayUpdateNeeded) {
|
||||
displayUpdate(horizon + 2, LCD_HEIGHT_PX);
|
||||
}
|
||||
// displayUpdate(0, LCD_HEIGHT_PX);
|
||||
});
|
||||
|
||||
// displayUpdate(0, LCD_HEIGHT_PX);
|
||||
|
||||
// draw_loop_x(img_loop, 0, 0, angle, LCD_WIDTH_PX);
|
||||
// draw_loop_x(img_castle, 0, 0, angle * 1.5, LCD_WIDTH_PX);
|
||||
// draw_loop_x(img_bush, 0, 0, angle * 2, LCD_WIDTH_PX);
|
||||
// Bdisp_PutDisp_DD();
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
if (state.totalFrameCount % 30 == 0) {
|
||||
printf("kartX: %f, kartY: %f\n", state.player.x, state.player.y);
|
||||
}
|
||||
// if (state.totalFrameCount % 30 == 0) {
|
||||
// printf("kartX: %f, kartY: %f\n", state.player.x, state.player.y);
|
||||
// }
|
||||
#endif
|
||||
|
||||
state.totalFrameCount += 1;
|
||||
|
@ -990,30 +840,28 @@ int main() {
|
|||
return Number(prompt("Track ID:", "0"));
|
||||
);
|
||||
#else
|
||||
trackId = 0;
|
||||
dclear(C_WHITE);
|
||||
drawText(8, 8, "F1 - Peach Circuit");
|
||||
drawText(8, 20, "F2 - Sunset Wilds");
|
||||
drawText(8, 32, "F3 - Sky Garden");
|
||||
displayUpdate(0, LCD_HEIGHT_PX);
|
||||
trackId = -1;
|
||||
while (trackId == -1) {
|
||||
key_event_t key = getkey();
|
||||
if (key.type != KEYEV_DOWN) continue;
|
||||
if (key.key == KEY_F1) trackId = 0;
|
||||
if (key.key == KEY_F2) trackId = 1;
|
||||
if (key.key == KEY_F3) trackId = 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
initData(trackId);
|
||||
|
||||
fillSky(0, LCD_HEIGHT_PX);
|
||||
|
||||
/* state.player.x = 3565.0 / 12;
|
||||
state.player.y = 2600.0 / 12;
|
||||
state.player.xVelocity = 0;
|
||||
state.player.yVelocity = 0;
|
||||
state.player.power = 0;
|
||||
state.player.reverse = 0;
|
||||
state.player.angle = 0;
|
||||
state.player.angularVelocity = 0;
|
||||
state.player.isThrottling = false;
|
||||
state.player.isReversing = false;
|
||||
state.player.isShooting = false;
|
||||
state.player.isTurningLeft = false;
|
||||
state.player.isTurningRight = false; */
|
||||
|
||||
initState();
|
||||
kartX = state.player.x * 12;
|
||||
kartY = state.player.y * 12;
|
||||
kartX = state.player.x;
|
||||
kartY = state.player.y;
|
||||
// Radians to degrees
|
||||
kartAngle = -state.player.angle * 180 / 3.1415926;
|
||||
kartAngle += 90;
|
||||
|
@ -1029,15 +877,5 @@ int main() {
|
|||
|
||||
runMainLoop(main_loop, 60);
|
||||
|
||||
/* color_t* VRAM = (color_t*)0xA8000000; // emu address of VRAM
|
||||
VRAM += (LCD_WIDTH_PX*y + x);
|
||||
short j;
|
||||
for (j=y; j<y+height; j++) {
|
||||
for (int i = x; i< x + width; i++) {
|
||||
*(VRAM++) = 0x07E0;
|
||||
}
|
||||
VRAM += LCD_WIDTH_PX - width;
|
||||
} */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
135
src/physics.c
135
src/physics.c
|
@ -5,7 +5,11 @@
|
|||
#include "./maths.h"
|
||||
#include "./buttons.h"
|
||||
#include "./state.h"
|
||||
#include "stdbool.h"
|
||||
#include "./data.h"
|
||||
#include "./particles.h"
|
||||
#include "./tilemap.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define angleWidth 192
|
||||
|
||||
|
@ -57,6 +61,9 @@ double dmod(double a, double b) {
|
|||
return a - (int)(a / b) * b;
|
||||
}
|
||||
|
||||
#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
|
||||
#define MAX(X, Y) (((X) < (Y)) ? (Y) : (X))
|
||||
|
||||
// #define maxSteerNormal 1
|
||||
// #define minSteerDrift 0.2 * (1.7 / 2.2)
|
||||
// #define neutralSteerDrift (1.7 / 2.2)
|
||||
|
@ -66,7 +73,115 @@ extern double minSteerDrift;
|
|||
extern double neutralSteerDrift;
|
||||
extern double maxSteerDrift;
|
||||
|
||||
void boostKart(Kart *kart, int amount) {
|
||||
kart->boostTime = MAX(kart->boostTime, amount);
|
||||
if (!kart->isPlayer) return;
|
||||
if (amount >= 100) {
|
||||
addParticle(2, LCD_WIDTH_PX / 2 - 28, LCD_HEIGHT_PX - 70, 0, 0);
|
||||
} else if (amount >= 50) {
|
||||
addParticle(1, LCD_WIDTH_PX / 2 - 28, LCD_HEIGHT_PX - 70, 0, 0);
|
||||
} else {
|
||||
addParticle(3, LCD_WIDTH_PX / 2 - 28, LCD_HEIGHT_PX - 70, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove this somehow or make it more clear
|
||||
#define scale 4
|
||||
|
||||
void updateWithControls(Kart *kart, ButtonState controls) {
|
||||
// Save the previous position, to restore if we hit a wall
|
||||
double oldKartY = kart->y;
|
||||
double oldKartX = kart->x;
|
||||
|
||||
// Get the tile the kart is on, and its type.
|
||||
// TODO: Use all the tiles the kart is touching?
|
||||
unsigned char currentTile = getTileID(kart->x / scale, kart->y / scale);
|
||||
enum TileType tileType = getTileType(currentTile);
|
||||
|
||||
bool isOffRoad = tileType == Offroad || tileType == Grass || tileType == ShallowWater;
|
||||
|
||||
if (tileType == BoostPad) {
|
||||
boostKart(kart, 100);
|
||||
} else if (tileType == JumpBar) {
|
||||
controls.hop = true;
|
||||
}
|
||||
|
||||
// If the kart is still drifting...
|
||||
if (kart->drifting && !isOffRoad) {
|
||||
if ((controls.left && kart->driftDir == -1) || (controls.right && kart->driftDir == 1)) {
|
||||
// Drift charge builds faster when holding the same direction as the drift
|
||||
kart->driftCharge += 2;
|
||||
} else {
|
||||
kart->driftCharge++;
|
||||
}
|
||||
} else {
|
||||
// If the kart is not drifting, or is off road, reset the drift charge to 0
|
||||
kart->driftCharge = 0;
|
||||
}
|
||||
|
||||
if (!controls.hop) {
|
||||
// When the player lets go of the drift button...
|
||||
if (kart->drifting && kart->driftCharge >= 60) {
|
||||
// apply the relevant boost...
|
||||
if (kart->driftCharge > 360) {
|
||||
boostKart(kart, 100);
|
||||
} else if (kart->driftCharge >= 180) {
|
||||
boostKart(kart, 50);
|
||||
} else {
|
||||
boostKart(kart, 20);
|
||||
}
|
||||
}
|
||||
// ...and cancel the drift
|
||||
kart->drifting = false;
|
||||
}
|
||||
|
||||
// If the hop button was pressed, and the kart is not currently hopping...
|
||||
if (controls.hop && !kart->lastHop && kart->hopStage == 0) {
|
||||
// ...start the hop animation.
|
||||
kart->hopStage = 1;
|
||||
if (controls.left || controls.right) {
|
||||
// If a direction is held, start a drift (this can also be done when the hop finishes)
|
||||
kart->drifting = true;
|
||||
kart->driftDir = controls.left ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If a hop is in progress...
|
||||
if (kart->hopStage != 0) {
|
||||
// ...continue the hop animation.
|
||||
kart->hopStage++;
|
||||
if (kart->hopStage >= 15) {
|
||||
kart->hopStage = 0;
|
||||
if (!kart->drifting && (controls.left || controls.right)) {
|
||||
// If a direction is held, start a drift
|
||||
kart->drifting = true;
|
||||
kart->driftDir = controls.left ? -1 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool boosting = false;
|
||||
if (kart->boostTime >= 0) {
|
||||
// If we are boosting, set a flag and decrement the remaining time
|
||||
kart->boostTime--;
|
||||
boosting = true;
|
||||
}
|
||||
|
||||
if (boosting) {
|
||||
// TODO: Remove this seemingly duplicate variable
|
||||
applyBoost = true;
|
||||
kart->power = maxPower;
|
||||
controls.accel = true;
|
||||
} else {
|
||||
applyBoost = false;
|
||||
}
|
||||
|
||||
if (!boosting && isOffRoad) {
|
||||
applyOffRoadDrag = true;
|
||||
} else {
|
||||
applyOffRoadDrag = false;
|
||||
}
|
||||
|
||||
bool canTurn = kart->power > 0.0025/* || car->reverse*/;
|
||||
|
||||
// Controls are reversed for now
|
||||
|
@ -132,12 +247,26 @@ void updateWithControls(Kart *kart, ButtonState controls) {
|
|||
kart->xVelocity += sin2(kart->angle) * (kart->power /* - kart->reverse */);
|
||||
kart->yVelocity += cos2(kart->angle) * (kart->power /* - kart->reverse */);
|
||||
|
||||
kart->x += kart->xVelocity;
|
||||
kart->y -= kart->yVelocity;
|
||||
kart->x += kart->xVelocity * 12;
|
||||
kart->y -= kart->yVelocity * 12;
|
||||
double calcDrag = applyOffRoadDrag ? offRoadDrag : drag;
|
||||
kart->xVelocity *= calcDrag;
|
||||
kart->yVelocity *= calcDrag;
|
||||
kart->angle += kart->angularVelocity;
|
||||
kart->angle = dmod(kart->angle, 3.1415926 * 2);
|
||||
kart->angularVelocity *= angularDrag;
|
||||
|
||||
unsigned char newTile = getTileID(kart->x / scale, kart->y / scale);
|
||||
|
||||
if (getTileType(newTile) == SolidBlock) {
|
||||
kart->x = oldKartX;
|
||||
kart->y = oldKartY;
|
||||
}
|
||||
|
||||
// Finish line is tile 254
|
||||
if (newTile == 254 && currentTile != 254) {
|
||||
kart->lapCount++;
|
||||
}
|
||||
|
||||
kart->lastHop = controls.hop;
|
||||
}
|
||||
|
|
|
@ -4,8 +4,11 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
#include "./buttons.h"
|
||||
#include "./data.h"
|
||||
|
||||
typedef struct {
|
||||
bool isPlayer;
|
||||
|
||||
double x;
|
||||
double y;
|
||||
double xVelocity;
|
||||
|
@ -22,6 +25,8 @@ typedef struct {
|
|||
int driftCharge;
|
||||
int boostTime;
|
||||
int lapCount;
|
||||
|
||||
bool lastHop;
|
||||
} Kart;
|
||||
|
||||
extern bool applyOffRoadDrag;
|
||||
|
|
|
@ -39,6 +39,7 @@ void draw(const struct image *img, int x, int y);
|
|||
void draw_partial(const struct image *img, int x, int y, int sx, int sy, int w, int h);
|
||||
void draw_flipped(const struct image *img, int x, int y);
|
||||
void draw_partial_flipped(const struct image *img, int x, int y, int sx, int sy, int w, int h);
|
||||
void draw_scaled(const struct image *img, int x, int y, float scaleX, float scaleY);
|
||||
|
||||
int get_width(const struct image* img);
|
||||
int get_height(const struct image* img);
|
||||
|
|
|
@ -72,7 +72,7 @@ void displayUpdate(int minY, int maxY) {
|
|||
|
||||
void drawText(int x, int y, const char *text) {
|
||||
dtext_opt(x, y, C_BLACK, C_WHITE, DTEXT_LEFT, DTEXT_TOP, text, -1);
|
||||
displayUpdate(y, y + 12);
|
||||
// displayUpdate(y, y + 12);
|
||||
}
|
||||
|
||||
int getTimeMS(void) {
|
||||
|
@ -108,6 +108,23 @@ void draw_partial_flipped(const struct image *img, int x, int y, int sx, int sy,
|
|||
dsubimage_p8_effect(x + img->xOffset + sx, y + img->yOffset + sy, img->data, sx, sy, w, h, IMAGE_HFLIP);
|
||||
}
|
||||
|
||||
void draw_scaled(const struct image *img, int x, int y, float scaleX, float scaleY) {
|
||||
// Create an image_linear_map
|
||||
struct image_linear_map map;
|
||||
image_scale(img->data, scaleX * (1 << 16), scaleY * (1 << 16), &map);
|
||||
// If x is negative, cut the image off on the left.
|
||||
const image_t* newData;
|
||||
if (x < 0) {
|
||||
// image_sub(const image_t *src, int x, int y, int w, int h, image_t *dst)
|
||||
newData = image_sub(img->data, -x, 0, img->data->width + x, img->data->height);
|
||||
} else {
|
||||
newData = img->data;
|
||||
}
|
||||
// Use it to draw the image
|
||||
// TODO: Free the created image or cache it
|
||||
image_linear(newData, image_at(image_create_vram(), x, y), &map);
|
||||
}
|
||||
|
||||
int get_width(const struct image* img) {
|
||||
return img->data->width;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ void draw(const struct image *img, int x, int y);
|
|||
void draw_partial(const struct image *img, int x, int y, int sx, int sy, int w, int h);
|
||||
void draw_flipped(const struct image *img, int x, int y);
|
||||
void draw_partial_flipped(const struct image *img, int x, int y, int sx, int sy, int w, int h);
|
||||
void draw_scaled(const struct image *img, int x, int y, float scaleX, float scaleY);
|
||||
|
||||
int get_width(const struct image* img);
|
||||
int get_height(const struct image* img);
|
||||
|
|
|
@ -126,6 +126,78 @@ void draw_partial_flipped(const struct image *img, int x, int y, int sx, int sy,
|
|||
}
|
||||
}
|
||||
|
||||
// void draw_scaled(const struct image *img, int x, int y, float scaleX, float scaleY) {
|
||||
// const unsigned short* data = img->data;
|
||||
// // The height and width of the sprite are the first two elements in the data array
|
||||
// int width = data[0];
|
||||
// int height = data[1];
|
||||
|
||||
// int screenWidth = width * scaleX;
|
||||
// int screenHeight = height * scaleY;
|
||||
|
||||
// // The offsets of the x and y positions are the third and fourth elements in the data array
|
||||
// x += data[2];
|
||||
// y += data[3];
|
||||
|
||||
// // Now draw the sprite
|
||||
// // The data array starts at index 4
|
||||
// color_t* datac = (color_t*) (data + 4);
|
||||
// for (int j = y; j < y + screenHeight; j++) {
|
||||
// for (int i = x; i < x + screenWidth; i++) {
|
||||
// // Skip if out of bounds
|
||||
// if (i < 0 || i >= LCD_WIDTH_PX || j < 0 || j >= LCD_HEIGHT_PX) {
|
||||
// continue;
|
||||
// }
|
||||
// color_t colour = datac[(int) ((j - y) / scaleY) * width + (int) ((i - x) / scaleX)];
|
||||
// if (colour != 0x4fe0) {
|
||||
// VRAM[j * LCD_WIDTH_PX + i] = colour;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
void draw_scaled(const struct image *img, int x, int y, float scaleX, float scaleY) {
|
||||
const unsigned short* data = img->data;
|
||||
// The height and width of the sprite are the first two elements in the data array
|
||||
int width = data[0];
|
||||
int height = data[1];
|
||||
|
||||
int screenWidth = width * scaleX;
|
||||
int screenHeight = height * scaleY;
|
||||
|
||||
// The offsets of the x and y positions are the third and fourth elements in the data array
|
||||
x += data[2];
|
||||
y += data[3];
|
||||
|
||||
// Calculate an offset for each pixel to be incremeneted by in 16:16 fixed point
|
||||
int offsetX = (1 << 16) / scaleX;
|
||||
int offsetY = (1 << 16) / scaleY;
|
||||
|
||||
int currentX = 0;
|
||||
int currentY = 0;
|
||||
|
||||
// Now draw the sprite
|
||||
// The data array starts at index 4
|
||||
color_t* datac = (color_t*) (data + 4);
|
||||
for (int j = y; j < y + screenHeight; j++) {
|
||||
currentX = 0;
|
||||
for (int i = x; i < x + screenWidth; i++) {
|
||||
int sampleX = currentX >> 16;
|
||||
int sampleY = currentY >> 16;
|
||||
// Skip if out of bounds
|
||||
if (i < 0 || i >= LCD_WIDTH_PX || j < 0 || j >= LCD_HEIGHT_PX) {
|
||||
continue;
|
||||
}
|
||||
color_t colour = datac[sampleY * width + sampleX];
|
||||
if (colour != 0x4fe0) {
|
||||
VRAM[j * LCD_WIDTH_PX + i] = colour;
|
||||
}
|
||||
currentX += offsetX;
|
||||
}
|
||||
currentY += offsetY;
|
||||
}
|
||||
}
|
||||
|
||||
// // Copy a sprite that loops around with an X offset
|
||||
// void CopySpriteLoopX(const void* datar, int x, int y, int width, int height, int xOffset, int drawWidth, int maskcolor) {
|
||||
// color_t* data = (color_t*)datar;
|
||||
|
|
|
@ -37,7 +37,7 @@ typedef enum {
|
|||
REC_KEY_DEBUG,
|
||||
REC_KEY_SAVE,
|
||||
REC_KEY_LOAD,
|
||||
REC_KEY_DEBUG_BOOST,
|
||||
// REC_KEY_FRAMECAP_TOGGLE,
|
||||
} keyType;
|
||||
|
||||
typedef struct {
|
||||
|
@ -104,12 +104,13 @@ void updateButtonState(ButtonState *state) {
|
|||
if (state->load) {
|
||||
addEvent(EVENT_PRESS, REC_KEY_LOAD);
|
||||
}
|
||||
if (state->debug_boost) {
|
||||
addEvent(EVENT_PRESS, REC_KEY_DEBUG_BOOST);
|
||||
}
|
||||
// if (state->framecap_toggle) {
|
||||
// addEvent(EVENT_PRESS, REC_KEY_FRAMECAP_TOGGLE);
|
||||
// }
|
||||
|
||||
if (recording.events[recording.numEvents - 1].type == EVENT_WAIT) {
|
||||
// If the last event was a wait event, increment the counter by 1
|
||||
// TODO: Check for overflow
|
||||
recording.events[recording.numEvents - 1].data++;
|
||||
} else {
|
||||
// Otherwise, add a new wait event
|
||||
|
|
|
@ -35,8 +35,9 @@ State state;
|
|||
void initState() {
|
||||
state = (State) {
|
||||
.player = (Kart) {
|
||||
.x = ((float) track.startX) / 12,
|
||||
.y = ((float) track.startY) / 12,
|
||||
.isPlayer = true,
|
||||
.x = ((float) track.startX),
|
||||
.y = ((float) track.startY),
|
||||
.xVelocity = 0,
|
||||
.yVelocity = 0,
|
||||
.power = 0,
|
||||
|
|
|
@ -22,6 +22,39 @@ unsigned char getTileID(short xPos, short yPos) {
|
|||
}
|
||||
}
|
||||
|
||||
// unsigned char getTileID(short l0, short l1) {
|
||||
// unsigned int si0, si1, si2;
|
||||
// si0 = l0;
|
||||
// si1 = l1;
|
||||
// si0 |= si1;
|
||||
// si1 = 2047u;
|
||||
// si0 = si0 <= si1;
|
||||
// if (si0) {
|
||||
// si0 = l1;
|
||||
// si1 = 65528u;
|
||||
// si0 &= si1;
|
||||
// si1 = 5u;
|
||||
// si0 <<= (si1 & 31);
|
||||
// si1 = l0;
|
||||
// si2 = 65528u;
|
||||
// si1 &= si2;
|
||||
// si2 = 3u;
|
||||
// si1 >>= (si2 & 31);
|
||||
// si0 += si1;
|
||||
// // si1 = 1024u;
|
||||
// // si0 += si1;
|
||||
// // si0 = load(si0);
|
||||
// si0 = tilemap[si0];
|
||||
// } else {
|
||||
// si0 = 0u;
|
||||
// }
|
||||
// return si0;
|
||||
// }
|
||||
|
||||
enum TileType getTileType(int tileID) {
|
||||
return (enum TileType) track.tileTypes[tileID];
|
||||
}
|
||||
|
||||
unsigned short samplePixel(short xPos, short yPos) {
|
||||
xPos += xOffset;
|
||||
yPos += yOffset;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
unsigned char getTileID(short xPos, short yPos);
|
||||
enum TileType getTileType(int tileID);
|
||||
unsigned short samplePixel(short xPos, short yPos);
|
||||
|
||||
#endif // _TILEMAP_H
|
||||
|
|
Loading…
Reference in New Issue