Many things, can't list them all
|
@ -0,0 +1,8 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="MakefileSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<MakefileProjectSettings>
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="version" value="2" />
|
||||
</MakefileProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
<component name="MakefileWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
</project>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
|
@ -10,6 +10,10 @@
|
|||
"display.h": "c",
|
||||
"math.h": "c",
|
||||
"generated_lut.h": "c",
|
||||
"stdbool.h": "c"
|
||||
"stdbool.h": "c",
|
||||
"SYSTEM.C": "cpp",
|
||||
"rtc.h": "c",
|
||||
"particles.h": "c",
|
||||
"images.h": "c"
|
||||
}
|
||||
}
|
2
Makefile
|
@ -119,7 +119,7 @@ browser: html/index.html
|
|||
emrun --browser=chromium --browser_args=--auto-open-devtools-for-tabs html/index.html
|
||||
|
||||
$(BUILD):
|
||||
@mkdir $@
|
||||
@mkdir -p $@
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
export CYGWIN := nodosfilewarning
|
||||
|
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 151 B |
After Width: | Height: | Size: 231 B |
After Width: | Height: | Size: 235 B |
14
build/main.d
|
@ -2,22 +2,32 @@ main.o: /home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/main.c \
|
|||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/./main.h \
|
||||
/home/heath/PrizmSDK-win-0.5.2/include/fxcg/display.h \
|
||||
/home/heath/PrizmSDK-win-0.5.2/include/fxcg/keyboard.h \
|
||||
/home/heath/PrizmSDK-win-0.5.2/include/fxcg/system.h \
|
||||
/home/heath/PrizmSDK-win-0.5.2/include/fxcg/misc.h \
|
||||
/home/heath/PrizmSDK-win-0.5.2/include/stddef.h \
|
||||
/home/heath/PrizmSDK-win-0.5.2/include/fxcg/rtc.h \
|
||||
/home/heath/PrizmSDK-win-0.5.2/include/fxcg/system.h \
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/./3d.h \
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/./tilemap.h \
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/./sprites.h \
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/./physics.h \
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/././buttons.h \
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/./buttons.h \
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/./debugHud.h \
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/./particles.h \
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/../data-headers/images.h
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/./main.h:
|
||||
/home/heath/PrizmSDK-win-0.5.2/include/fxcg/display.h:
|
||||
/home/heath/PrizmSDK-win-0.5.2/include/fxcg/keyboard.h:
|
||||
/home/heath/PrizmSDK-win-0.5.2/include/fxcg/system.h:
|
||||
/home/heath/PrizmSDK-win-0.5.2/include/fxcg/misc.h:
|
||||
/home/heath/PrizmSDK-win-0.5.2/include/stddef.h:
|
||||
/home/heath/PrizmSDK-win-0.5.2/include/fxcg/rtc.h:
|
||||
/home/heath/PrizmSDK-win-0.5.2/include/fxcg/system.h:
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/./3d.h:
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/./tilemap.h:
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/./sprites.h:
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/./physics.h:
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/././buttons.h:
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/./buttons.h:
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/./debugHud.h:
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/./particles.h:
|
||||
/home/heath/PrizmSDK-win-0.5.2/projects/mario-kart/src/../data-headers/images.h:
|
||||
|
|
BIN
build/main.o
|
@ -0,0 +1,2 @@
|
|||
https://www.spriters-resource.com/fullview/5477/
|
||||
https://www.spriters-resource.com/game_boy_advance/mariokartsupercircuit/sheet/5490/
|
|
@ -29,13 +29,13 @@ int setKeyState(unsigned char key, unsigned char state) {
|
|||
}
|
||||
|
||||
int keyDownEvent(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData) {
|
||||
printf("keyDownEvent: %d\n", keyEvent->keyCode);
|
||||
// printf("keyDownEvent: %d\n", (int) keyEvent->keyCode);
|
||||
setKeyState(keyEvent->keyCode, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int keyUpEvent(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData) {
|
||||
printf("keyUpEvent: %d\n", keyEvent->keyCode);
|
||||
// printf("keyUpEvent: %d\n", (int) keyEvent->keyCode);
|
||||
setKeyState(keyEvent->keyCode, 0);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
void PowerOff(int displayLogo) {
|
||||
// nop
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// This adds in syscalls for interfacing with the OS and hardware.
|
||||
|
||||
void SetAutoPowerOffTime(int durationInMinutes);
|
||||
int GetAutoPowerOffTime(); //returns duration in minutes
|
||||
|
||||
void SetBacklightDuration(char durationInHalfMinutes);
|
||||
char GetBacklightDuration(); //returns duration in half-minutes
|
||||
|
||||
void SetBatteryType(int type);
|
||||
int GetBatteryType(void);
|
||||
|
||||
int GetMainBatteryVoltage(int one); //parameter should be 1
|
||||
void PowerOff(int displayLogo);
|
||||
void Restart();
|
||||
void SpecialMatrixcodeProcessing(int*col, int*row);
|
||||
void TestMode(int);
|
||||
void*GetStackPtr(void);
|
||||
|
||||
void SetSetupSetting(unsigned int SystemParameterNo, unsigned char SystemParameterValue);
|
||||
unsigned char GetSetupSetting(unsigned int SystemParameterNo);
|
||||
|
||||
int Timer_Install(int InternalTimerID, void (*hander)(void), int elapse);
|
||||
int Timer_Deinstall(int InternalTimerID);
|
||||
int Timer_Start(int InternalTimerID);
|
||||
int Timer_Stop(int InternalTimerID);
|
||||
|
||||
void TakeScreenshot(void);
|
||||
void TakeScreenshot2(void); //seems to be the same as the one above
|
||||
|
||||
void DisplayMainMenu(void);
|
||||
|
||||
//Hold program execution:
|
||||
void OS_InnerWait_ms(int);
|
||||
|
||||
void CMT_Delay_100micros(int); //does CMT stand for Composable Memory Transactions? Couldn't find documentation on this
|
||||
void CMT_Delay_micros(int); // nor on this (gbl08ma)
|
||||
|
||||
void SetQuitHandler(void (*)()); // sets callback to be run when user exits through the main menu from one app to another. eActivity uses this in the "Save file?" dialog
|
||||
|
||||
void Alpha_SetData( char VarName, void* Src );
|
||||
void Alpha_GetData( char VarName, void* Dest );
|
||||
|
||||
int CLIP_Store( unsigned char*buffer, int length ); // stores buffer of length length in the system clipboard.
|
||||
|
||||
int MB_ElementCount(char* buf); // like strlen but for the graphical length of multibyte strings
|
||||
int MB_IsLead(char c); // returns 1 if the character is the first byte of a multibyte char
|
||||
|
||||
int GlibGetOSVersionInfo(char *major, char *minor, short int *c, short int *d);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,122 @@
|
|||
# Reads images, converts the colour data to RGB565, and writes it to a header file.
|
||||
# 0x4fe0 is used as the transparent colour.
|
||||
|
||||
from PIL import Image
|
||||
import sys
|
||||
import os
|
||||
|
||||
def toData(path):
|
||||
img = Image.open(path)
|
||||
img = img.convert("RGBA")
|
||||
outData = []
|
||||
|
||||
# Crop step
|
||||
# Create a copy of the image with transparent pixels set to black, and non-transparent pixels set to white.
|
||||
# This is used so that getbbox() can be used to crop out the transparent pixels.
|
||||
newImg = img.copy()
|
||||
for x in range(newImg.size[0]):
|
||||
for y in range(newImg.size[1]):
|
||||
if newImg.getpixel((x, y))[3] < 128:
|
||||
newImg.putpixel((x, y), (0, 0, 0, 0))
|
||||
else:
|
||||
newImg.putpixel((x, y), (255, 255, 255, 255))
|
||||
box = newImg.getbbox()
|
||||
|
||||
# Crop the image to the box.
|
||||
img = img.crop(box)
|
||||
|
||||
# Add the height and width to the header.
|
||||
outData.append(img.size[0])
|
||||
outData.append(img.size[1])
|
||||
|
||||
# Add the offset (the first two elements of box) to the header.
|
||||
outData.append(box[0])
|
||||
outData.append(box[1])
|
||||
|
||||
# Iterate through the pixels.
|
||||
for y in range(img.size[1]):
|
||||
for x in range(img.size[0]):
|
||||
# Get the colour data.
|
||||
r, g, b, a = img.getpixel((x, y))
|
||||
# print(r, g, b, a)
|
||||
# Convert to RGB565.
|
||||
rgb = ((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | (b >> 3);
|
||||
if (rgb == 0x4fe0):
|
||||
rgb = 0x4fe1
|
||||
if a < 128:
|
||||
rgb = 0x4fe0
|
||||
outData.append(rgb)
|
||||
return outData
|
||||
|
||||
def dataToCFile(data, name):
|
||||
header = f"extern const unsigned short img_{name}[{len(data)}];"
|
||||
out = f"const unsigned short img_{name}[{len(data)}] = {{"
|
||||
for i in data:
|
||||
out += f"0x{i:04x}, "
|
||||
out = out[:-2] + "};"
|
||||
return header, out
|
||||
|
||||
# def multiDataToHeader(dataArray, filename):
|
||||
# # Check that the lengths of the data arrays are the same.
|
||||
# for i in range(len(dataArray)):
|
||||
# if len(dataArray[i]) != len(dataArray[0]):
|
||||
# raise Exception("Images must have the same dimensions.")
|
||||
|
||||
# out = f"const unsigned short imgs_{filename}[{len(dataArray)}][{len(dataArray[0])}] = {{"
|
||||
# for i in range(len(dataArray)):
|
||||
# out += "{"
|
||||
# for j in range(len(dataArray[i])):
|
||||
# out += f"0x{dataArray[i][j]:04x}, "
|
||||
# out = out[:-2] + "}, "
|
||||
# out = out[:-2] + "};"
|
||||
# return out
|
||||
|
||||
def multiDataToCFile(dataArray, filename):
|
||||
result = ""
|
||||
header = ""
|
||||
for index, data in enumerate(dataArray):
|
||||
head, data = dataToCFile(data, f"{filename.split('.')[0]}_{index}")
|
||||
result += data + "\n"
|
||||
header += head + "\n"
|
||||
result += "const unsigned short* imgs_" + filename.split('.')[0] + "[" + str(len(dataArray)) + "] = {"
|
||||
for index, data in enumerate(dataArray):
|
||||
result += f"img_{filename.split('.')[0]}_{index}, "
|
||||
result = result[:-2] + "};"
|
||||
header += "extern const unsigned short* imgs_" + filename.split('.')[0] + "[" + str(len(dataArray)) + "];"
|
||||
return header, result
|
||||
|
||||
all = ""
|
||||
allHeader = ""
|
||||
# Loop over the PNG files in ../assets/img/ (relative to the script)
|
||||
os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
||||
for file in os.listdir("../assets/img/"):
|
||||
if file.endswith(".png"):
|
||||
header, result = dataToCFile(toData("../assets/img/" + file), file.split('.')[0])
|
||||
print("Converted " + file)
|
||||
all += result + "\n"
|
||||
allHeader += header + "\n"
|
||||
# If it's a directory, create an array containing the header for each image in the directory.
|
||||
elif os.path.isdir("../assets/img/" + file):
|
||||
dataArray = []
|
||||
for n in range(9999):
|
||||
# Check if n.png exists, and exit the loop if it doesn't.
|
||||
subFile = f"../assets/img/{file}/{n}.png"
|
||||
if not os.path.isfile(subFile):
|
||||
break
|
||||
print("Converting " + subFile)
|
||||
result = toData(subFile)
|
||||
dataArray.append(result)
|
||||
header, result = multiDataToCFile(dataArray, file)
|
||||
print("Converted " + file)
|
||||
all += result + "\n"
|
||||
allHeader += header + "\n"
|
||||
else:
|
||||
print("Skipping " + file)
|
||||
|
||||
# Write to a file.
|
||||
with open("../data-headers/images.c", "w") as f:
|
||||
f.write(all)
|
||||
|
||||
# Write the header file.
|
||||
with open("../data-headers/images.h", "w") as f:
|
||||
f.write(allHeader)
|
|
@ -1,79 +0,0 @@
|
|||
# Reads images, converts the colour data to RGB565, and writes it to a header file.
|
||||
# 0x4fe0 is used as the transparent colour.
|
||||
|
||||
from PIL import Image
|
||||
import sys
|
||||
import os
|
||||
|
||||
def toData(path):
|
||||
img = Image.open(path)
|
||||
img = img.convert("RGBA")
|
||||
outData = []
|
||||
# Add the height and width to the header.
|
||||
outData.append(img.size[0])
|
||||
outData.append(img.size[1])
|
||||
# Iterate through the pixels.
|
||||
for y in range(img.size[1]):
|
||||
for x in range(img.size[0]):
|
||||
# Get the colour data.
|
||||
r, g, b, a = img.getpixel((x, y))
|
||||
# print(r, g, b, a)
|
||||
# Convert to RGB565.
|
||||
rgb = ((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | (b >> 3);
|
||||
if (rgb == 0x4fe0):
|
||||
rgb = 0x4fe1
|
||||
if a < 128:
|
||||
rgb = 0x4fe0
|
||||
outData.append(rgb)
|
||||
return outData
|
||||
|
||||
def dataToHeader(data, filename):
|
||||
out = f"const unsigned short img_{filename.split('.')[0]}[{len(data)}] = {{"
|
||||
for i in data:
|
||||
out += f"0x{i:04x}, "
|
||||
out = out[:-2] + "};"
|
||||
return out
|
||||
|
||||
def multiDataToHeader(dataArray, filename):
|
||||
# Check that the lengths of the data arrays are the same.
|
||||
for i in range(len(dataArray)):
|
||||
if len(dataArray[i]) != len(dataArray[0]):
|
||||
raise Exception("Images must have the same dimensions.")
|
||||
|
||||
out = f"const unsigned short imgs_{filename}[{len(dataArray)}][{len(dataArray[0])}] = {{"
|
||||
for i in range(len(dataArray)):
|
||||
out += "{"
|
||||
for j in range(len(dataArray[i])):
|
||||
out += f"0x{dataArray[i][j]:04x}, "
|
||||
out = out[:-2] + "}, "
|
||||
out = out[:-2] + "};"
|
||||
return out
|
||||
|
||||
|
||||
all = ""
|
||||
# Loop over the PNG files in ../assets/img/ (relative to the script)
|
||||
os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
||||
for file in os.listdir("../assets/img/"):
|
||||
if file.endswith(".png"):
|
||||
result = dataToHeader(toData("../assets/img/" + file), file)
|
||||
print("Converted " + file)
|
||||
all += result + "\n"
|
||||
# If it's a directory, create an array containing the header for each image in the directory.
|
||||
elif os.path.isdir("../assets/img/" + file):
|
||||
dataArray = []
|
||||
for n in range(9999):
|
||||
# Check if n.png exists, and exit the loop if it doesn't.
|
||||
subFile = f"../assets/img/{file}/{n}.png"
|
||||
if not os.path.isfile(subFile):
|
||||
break
|
||||
print("Converting " + subFile)
|
||||
result = toData(subFile)
|
||||
dataArray.append(result)
|
||||
result = multiDataToHeader(dataArray, file)
|
||||
print("Converted " + file)
|
||||
all += result + "\n"
|
||||
else:
|
||||
print("Skipping " + file)
|
||||
# Write the header to a file.
|
||||
with open("../data-headers/images.h", "w") as f:
|
||||
f.write(all)
|
|
@ -0,0 +1,68 @@
|
|||
import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
# Analyses the size of arrays in C files and lists them in order of size.
|
||||
|
||||
group = r"(?:\[([a-zA-Z0-9_ ]*)\])"
|
||||
regex = r"^ *(?:const )?([a-zA-Z0-9_ ]*)" + group + ((group + "?") * 3) + r"\n? *\n?=\n? *\n?\{"
|
||||
regex = re.compile(regex, re.MULTILINE)
|
||||
|
||||
sizes = {
|
||||
"char": 1,
|
||||
"short": 2,
|
||||
"int": 4,
|
||||
"long": 8,
|
||||
"float": 4,
|
||||
"double": 8
|
||||
}
|
||||
|
||||
aliases = {
|
||||
"angleWidth": 192,
|
||||
"totalHeight": 108
|
||||
}
|
||||
|
||||
includedDirectories = [
|
||||
"./src/",
|
||||
"./data-headers/"
|
||||
]
|
||||
|
||||
os.chdir(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../"))
|
||||
|
||||
# Get all the files in the included directories.
|
||||
files = []
|
||||
for directory in includedDirectories:
|
||||
for file in os.listdir(directory):
|
||||
if file.endswith(".c") or file.endswith(".h"):
|
||||
files.append(os.path.join(directory, file))
|
||||
|
||||
# Read each file and get the size of each array.
|
||||
arrays = []
|
||||
for file in files:
|
||||
with open(file, "r") as f:
|
||||
content = f.read()
|
||||
# The first group is the name and type of the array, the rest are the dimensions.
|
||||
for match in regex.finditer(content):
|
||||
nameAndType = match.group(1)
|
||||
name = nameAndType.split(" ")[-1]
|
||||
typeName = " ".join(nameAndType.split(" ")[:-1])
|
||||
typeSize = sizes[typeName.split("unsigned ")[-1]]
|
||||
|
||||
dimensions = [match.group(i) for i in range(2, len(match.groups()) + 1)]
|
||||
# Filter out the None values.
|
||||
dimensions = [dimension for dimension in dimensions if dimension is not None]
|
||||
# Resolve the aliases.
|
||||
for alias in aliases:
|
||||
if alias in dimensions:
|
||||
dimensions[dimensions.index(alias)] = aliases[alias]
|
||||
# Multiply the dimensions together.
|
||||
size = typeSize
|
||||
for dimension in dimensions:
|
||||
size *= int(dimension)
|
||||
arrays.append((name, size))
|
||||
|
||||
# Sort the arrays by size - biggest to smallest.
|
||||
arrays.sort(key=lambda x: x[1], reverse=True)
|
||||
# Print the arrays with human-readable sizes in KB.
|
||||
for array in arrays:
|
||||
print(f"{array[0]}: {array[1] / 1024:.2f} KB")
|
32
src/3d.c
|
@ -1,11 +1,20 @@
|
|||
#include "./3d.h"
|
||||
|
||||
#include <fxcg/display.h>
|
||||
|
||||
#include "./main.h"
|
||||
#include "./tilemap.h"
|
||||
#include "./maths.h"
|
||||
|
||||
#include "../data-headers/generated_lut.h"
|
||||
|
||||
#define LCD_WIDTH_PX 384
|
||||
#define LCD_HEIGHT_PX 216
|
||||
|
||||
inline void setPixel(int x, int y, color_t color) {
|
||||
VRAM[y * LCD_WIDTH_PX + x] = color;
|
||||
}
|
||||
|
||||
unsigned short getScreenPixel(unsigned short x, unsigned short y) {
|
||||
// __builtin_expect(x == (int)(LUT_WIDTH / 2), 0);
|
||||
// if (x < (int)(LUT_WIDTH / 2)) {
|
||||
|
@ -27,4 +36,27 @@ unsigned short getScreenPixel(unsigned short x, unsigned short y) {
|
|||
return samplePixel(xPos, yPos);
|
||||
}
|
||||
|
||||
void new3D() {
|
||||
int angleCos = fpcos(angle);
|
||||
int angleSin = fpsin(angle);
|
||||
for (unsigned short y = horizon + 2; y < LCD_HEIGHT_PX; y++) {
|
||||
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;
|
||||
|
||||
// Rotate by angle
|
||||
int newX = ((x2 * angleCos) >> 15) + ((y2 * angleSin) >> 15);
|
||||
int newY = ((y2 * angleCos) >> 15) - ((x2 * angleSin) >> 15);
|
||||
|
||||
color_t col = samplePixel(newX >> 1, newY >> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
2
src/3d.h
|
@ -1,7 +1,7 @@
|
|||
#ifndef _3D_H_
|
||||
#define _3D_H_
|
||||
|
||||
unsigned char getTileType(short xPos, short yPos);
|
||||
unsigned short getScreenPixel(unsigned short x, unsigned short y);
|
||||
void new3D();
|
||||
|
||||
#endif // _3D_H_
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
#include <fxcg/keyboard.h>
|
||||
|
||||
buttonState buttons = {0};
|
||||
buttonState lastButtons = {0};
|
||||
ButtonState buttons = {0};
|
||||
ButtonState lastButtons = {0};
|
||||
|
||||
// https://www.cemetech.net/forum/viewtopic.php?p=173836&sid=9eabb0dbeddeeb6507c19c8a65dbe249
|
||||
#ifndef FXCG_MOCK
|
||||
|
|
|
@ -14,10 +14,10 @@ typedef struct {
|
|||
bool accel;
|
||||
bool hop;
|
||||
bool debug;
|
||||
} buttonState;
|
||||
} ButtonState;
|
||||
|
||||
extern buttonState buttons;
|
||||
extern buttonState lastButtons;
|
||||
extern ButtonState buttons;
|
||||
extern ButtonState lastButtons;
|
||||
|
||||
void scanButtons();
|
||||
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
#ifndef FXCG_MOCK
|
||||
|
||||
#include "./debugHud.h"
|
||||
|
||||
#include <fxcg/display.h>
|
||||
#include <fxcg/rtc.h>
|
||||
|
||||
#include "./main.h"
|
||||
#include "./buttons.h"
|
||||
|
||||
int lastTime = 0;
|
||||
int debugType = 0;
|
||||
int fpsCount = 0;
|
||||
int currentFps = 0;
|
||||
|
||||
void handleDebugHud() {
|
||||
if (buttons.debug && !lastButtons.debug) {
|
||||
debugType++;
|
||||
debugType = debugType % 3;
|
||||
if (!debugType) {
|
||||
// Put the sky back
|
||||
fillSky(24, 34);
|
||||
Bdisp_PutDisp_DD_stripe(24, 34);
|
||||
}
|
||||
}
|
||||
|
||||
int currentTime = RTC_GetTicks();
|
||||
|
||||
if (debugType == 1) {
|
||||
int x = 8;
|
||||
int y = 0;
|
||||
|
||||
char buffer[17] = "FPS: ";
|
||||
itoa(currentFps, (unsigned char*)buffer + 5);
|
||||
|
||||
PrintMiniMini(&x, &y, buffer, 0, COLOR_BLACK, 0);
|
||||
Bdisp_PutDisp_DD_stripe(24, 34);
|
||||
} else if (debugType == 2) {
|
||||
int x = 8;
|
||||
int y = 0;
|
||||
|
||||
char buffer[17] = "Time: ";
|
||||
itoa((totalFrameCount / 38), (unsigned char*)buffer + 6);
|
||||
|
||||
PrintMiniMini(&x, &y, buffer, 0, COLOR_BLACK, 0);
|
||||
Bdisp_PutDisp_DD_stripe(24, 34);
|
||||
}
|
||||
|
||||
// If 1 second has passed
|
||||
if (currentTime - lastTime >= 128) {
|
||||
lastTime = currentTime;
|
||||
currentFps = fpsCount;
|
||||
fpsCount = 0;
|
||||
}
|
||||
fpsCount++;
|
||||
}
|
||||
|
||||
#endif // FXCG_MOCK
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef _DEBUGHUD_H
|
||||
#define _DEBUGHUD_H
|
||||
|
||||
#ifndef FXCG_MOCK
|
||||
|
||||
void handleDebugHud();
|
||||
|
||||
#endif // FXCG_MOCK
|
||||
|
||||
#endif // _DEBUGHUD_H
|
|
@ -0,0 +1 @@
|
|||
#include "../data-headers/images.c"
|
230
src/main.c
|
@ -2,10 +2,10 @@
|
|||
|
||||
#include <fxcg/display.h>
|
||||
#include <fxcg/keyboard.h>
|
||||
#include <fxcg/system.h>
|
||||
#ifndef FXCG_MOCK
|
||||
#include <fxcg/misc.h>
|
||||
#include <fxcg/rtc.h>
|
||||
#include <fxcg/system.h>
|
||||
|
||||
#define debug_printf(...)
|
||||
#else
|
||||
|
@ -18,9 +18,12 @@
|
|||
#endif
|
||||
|
||||
#include "./3d.h"
|
||||
#include "./tilemap.h"
|
||||
#include "./sprites.h"
|
||||
#include "./physics.h"
|
||||
#include "./buttons.h"
|
||||
#include "./debugHud.h"
|
||||
#include "./particles.h"
|
||||
|
||||
#include "../data-headers/images.h"
|
||||
|
||||
|
@ -104,6 +107,7 @@ void cameraBehind(short x, short y, short objectAngle, short distance) {
|
|||
xOffset = x - cos(-objectAngle) * distance;
|
||||
}
|
||||
|
||||
// TODO: max and mix
|
||||
void fillSky(unsigned short yMin, unsigned short yMax) {
|
||||
/* for (unsigned short x = 0; x < LCD_WIDTH_PX; x++) {
|
||||
for (unsigned short y = yMin; y < yMax; y++) {
|
||||
|
@ -161,12 +165,8 @@ float kartVel = 0;
|
|||
float kartAngle = 90;
|
||||
#define kartSpeed 2
|
||||
|
||||
int debugType = 0;
|
||||
|
||||
// For framerate counter
|
||||
int lastTime;
|
||||
int fpsCount = 0;
|
||||
int totalFrameCount = 0;
|
||||
int totalFrameCount = 0;
|
||||
|
||||
int jitter = 0;
|
||||
int hopStage = 0;
|
||||
|
@ -176,6 +176,7 @@ const int hopAnim[15] = {
|
|||
4, 3, 2, 1, 1,
|
||||
};
|
||||
bool drifting = false;
|
||||
int driftDir = 0;
|
||||
|
||||
Car kart;
|
||||
|
||||
|
@ -184,54 +185,9 @@ void main_loop() {
|
|||
scanButtons();
|
||||
|
||||
#ifndef FXCG_MOCK
|
||||
int currentTime = RTC_GetTicks();
|
||||
// If 1 second has passed, print framerate
|
||||
if (currentTime - lastTime >= 128) {
|
||||
lastTime = currentTime;
|
||||
|
||||
if (debugType == 1) {
|
||||
int x = 8;
|
||||
int y = 0;
|
||||
|
||||
char buffer[17] = "FPS: ";
|
||||
itoa(fpsCount, (unsigned char*)buffer + 5);
|
||||
|
||||
PrintMiniMini(&x, &y, buffer, 0, COLOR_BLACK, 0);
|
||||
Bdisp_PutDisp_DD_stripe(24, 34);
|
||||
} else if (debugType == 2) {
|
||||
int x = 8;
|
||||
int y = 0;
|
||||
|
||||
char buffer[17] = "Time: ";
|
||||
itoa((totalFrameCount / 38), (unsigned char*)buffer + 6);
|
||||
|
||||
PrintMiniMini(&x, &y, buffer, 0, COLOR_BLACK, 0);
|
||||
Bdisp_PutDisp_DD_stripe(24, 34);
|
||||
}
|
||||
fpsCount = 0;
|
||||
}
|
||||
handleDebugHud();
|
||||
#endif
|
||||
|
||||
// Grass or sand = more friction
|
||||
// unsigned char currentTile = getTileType(kartX / scale, kartY / scale);
|
||||
// if (currentTile == 0 || currentTile == 7 || currentTile == 9 || currentTile == 12 || currentTile == 14 || currentTile == 15 || currentTile == 50 || currentTile == 52) {
|
||||
// kartVel *= 0.8;
|
||||
// } else {
|
||||
// kartVel *= 0.9;
|
||||
// }
|
||||
// if (kartVel < 1.42) {
|
||||
// kartVel = 0;
|
||||
// }
|
||||
// float oldKartX = kartX;
|
||||
// float oldKartY = kartY;
|
||||
// kartY += kartVel * sin(-kartAngle);
|
||||
// kartX += kartVel * cos(-kartAngle);
|
||||
// unsigned char newTile = getTileType(kartX / scale, kartY / scale);
|
||||
// if (newTile >= 240 && newTile <= 243) { // Barrier
|
||||
// kartX = oldKartX;
|
||||
// kartY = oldKartY;
|
||||
// }
|
||||
|
||||
unsigned char currentTile = getTileType(kartX / scale, kartY / scale);
|
||||
if (currentTile == 0 || currentTile == 3 || currentTile == 4 || currentTile == 7 || currentTile == 8 ||
|
||||
currentTile == 9 || currentTile == 10 || currentTile == 12 || currentTile == 13 || currentTile == 14 ||
|
||||
|
@ -243,47 +199,73 @@ void main_loop() {
|
|||
drag = 0.9;
|
||||
}
|
||||
|
||||
// kartVel += kartSpeed;
|
||||
|
||||
// int key = PRGM_GetKey();
|
||||
|
||||
ControlState controls = {
|
||||
up: buttons.accel,
|
||||
down: 0,
|
||||
left: buttons.right,
|
||||
right: buttons.left
|
||||
};
|
||||
|
||||
turnSpeed = drifting ? 0.003: 0.002;
|
||||
|
||||
updateWithControls(&kart, controls);
|
||||
|
||||
kartX = kart.x * 12;
|
||||
kartY = kart.y * 12;
|
||||
// Radians to degrees
|
||||
kartAngle = -kart.angle * 180 / 3.1415926;
|
||||
kartAngle += 90;
|
||||
|
||||
cameraBehind(kartX, kartY, kartAngle, 150); // TODO: calculate this rather than guessing
|
||||
|
||||
/* if (shiftPressed) {
|
||||
kartVel += kartSpeed;
|
||||
} */
|
||||
// turnSpeed = drifting ? 0.003: 0.002;
|
||||
|
||||
if (!buttons.hop) {
|
||||
drifting = false;
|
||||
}
|
||||
|
||||
// #define maxSteerAnim 10
|
||||
int maxSteerAnim = drifting ? 20 : 10;
|
||||
if (buttons.left && !buttons.right/* && kartVel > 3 */) {
|
||||
if (buttons.hop && !lastButtons.hop && hopStage == 0) {
|
||||
hopStage = 1;
|
||||
if (buttons.left || buttons.right) {
|
||||
drifting = true;
|
||||
driftDir = buttons.left ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (hopStage != 0) {
|
||||
hopStage++;
|
||||
if (hopStage >= 15) {
|
||||
hopStage = 0;
|
||||
if (!drifting && (buttons.left || buttons.right)) {
|
||||
drifting = true;
|
||||
driftDir = buttons.left ? -1 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if (drifting) {
|
||||
// debug_printf("driftDir: %d\n", driftDir);
|
||||
if (driftDir == 1) {
|
||||
buttons.right = true;
|
||||
buttons.left = false;
|
||||
} else {
|
||||
buttons.left = true;
|
||||
buttons.right = false;
|
||||
}
|
||||
} */
|
||||
|
||||
double oldKartY = kart.y;
|
||||
double oldKartX = kart.x;
|
||||
|
||||
updateWithControls(&kart, buttons);
|
||||
|
||||
unsigned char newTile = getTileType(kart.x * 12 / scale, kart.y * 12 / scale);
|
||||
if (newTile >= 240 && newTile <= 243) { // Barrier
|
||||
kart.x = oldKartX;
|
||||
kart.y = oldKartY;
|
||||
}
|
||||
|
||||
kartX = kart.x * 12;
|
||||
kartY = kart.y * 12;
|
||||
|
||||
// Radians to degrees
|
||||
kartAngle = -kart.angle * 180 / 3.1415926;
|
||||
kartAngle += 90;
|
||||
|
||||
// TODO: no / 2 when lower FOV?
|
||||
cameraBehind(kartX, kartY, kartAngle, 150 / 2); // TODO: calculate this rather than guessing
|
||||
|
||||
// maxSteerAnim = drifting ? 20 : 10;
|
||||
#define maxSteerAnim 10
|
||||
/* if (buttons.left && !buttons.right) {
|
||||
kartAngle -= kartVel / 10;
|
||||
|
||||
kartSteerAnim++;
|
||||
if (kartSteerAnim > maxSteerAnim) {
|
||||
kartSteerAnim = maxSteerAnim;
|
||||
}
|
||||
} else if (buttons.right && !buttons.left/* && kartVel > 3 */) {
|
||||
} else if (buttons.right && !buttons.left) {
|
||||
kartAngle += kartVel / 10;
|
||||
|
||||
kartSteerAnim--;
|
||||
|
@ -302,7 +284,7 @@ void main_loop() {
|
|||
kartSteerAnim = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
// Control the distance
|
||||
/* if (keydown(KEY_PRGM_UP)) {
|
||||
|
@ -312,16 +294,6 @@ void main_loop() {
|
|||
distance -= 2;
|
||||
} */
|
||||
|
||||
if (buttons.debug && !lastButtons.debug) {
|
||||
debugType++;
|
||||
debugType = debugType % 3;
|
||||
if (!debugType) {
|
||||
// Put the sky back
|
||||
fillSky(24, 34);
|
||||
Bdisp_PutDisp_DD_stripe(24, 34);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef FXCG_MOCK
|
||||
if (keydown(KEY_PRGM_MENU)) {
|
||||
// Allow the OS to handle exiting to the menu
|
||||
|
@ -341,9 +313,9 @@ void main_loop() {
|
|||
|
||||
kartAngle = fmod(kartAngle, 360);
|
||||
|
||||
angle = fmod(kartAngle + 45, 360) * angleWidth / 90;
|
||||
angle = fmod(kartAngle + 90, 360) * angleWidth / 90;
|
||||
|
||||
for (unsigned short x = 0; x < LCD_WIDTH_PX / 2; x++) {
|
||||
/* for (unsigned short x = 0; x < LCD_WIDTH_PX / 2; x++) {
|
||||
index2 = x + angle;
|
||||
index2 = mod(index2, (angleWidth * 4));
|
||||
element = mod(index2, angleWidth);
|
||||
|
@ -353,38 +325,58 @@ void main_loop() {
|
|||
setPixel(x * 2, y, thing);
|
||||
setPixel(x * 2 + 1, y, thing);
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
new3D();
|
||||
|
||||
jitter++;
|
||||
if (abs_double(kart.xVelocity) + abs_double(kart.yVelocity) < 0.02) {
|
||||
jitter = 0;
|
||||
} else if (abs_double(kart.xVelocity) + abs_double(kart.yVelocity) < 0.30) {
|
||||
jitter = (totalFrameCount / 4) % 2;
|
||||
jitter = (totalFrameCount / 4) % 4;
|
||||
} else if (abs_double(kart.xVelocity) + abs_double(kart.yVelocity) < 0.50) {
|
||||
jitter = (totalFrameCount / 3) % 2;
|
||||
jitter = (totalFrameCount / 3) % 4;
|
||||
} else if (abs_double(kart.xVelocity) + abs_double(kart.yVelocity) < 1) {
|
||||
jitter = (totalFrameCount / 2) % 2;
|
||||
jitter = (totalFrameCount / 2) % 4;
|
||||
} else {
|
||||
jitter = totalFrameCount % 2;
|
||||
jitter = totalFrameCount % 4;
|
||||
}
|
||||
|
||||
// debug_printf("totalFrameCount: %d\n", totalFrameCount);
|
||||
|
||||
if (buttons.hop && !lastButtons.hop && hopStage == 0) {
|
||||
hopStage = 1;
|
||||
if (buttons.left || buttons.right) {
|
||||
drifting = true;
|
||||
int targetAnim = 0;
|
||||
if (buttons.left && !buttons.right) {
|
||||
targetAnim = maxSteerAnim;
|
||||
} else if (buttons.right && !buttons.left) {
|
||||
targetAnim = -maxSteerAnim;
|
||||
} else {
|
||||
targetAnim = 0;
|
||||
}
|
||||
|
||||
if (drifting) {
|
||||
targetAnim += (driftDir == -1) ? 10 : -10;
|
||||
if (driftDir == 1 && targetAnim > -7) {
|
||||
targetAnim = -7;
|
||||
}
|
||||
if (driftDir == -1 && targetAnim < 7) {
|
||||
targetAnim = 7;
|
||||
}
|
||||
// debug_printf("driftDir: %d, targetAnim: %d\n", driftDir, targetAnim);
|
||||
if (totalFrameCount % 8 == 0) {
|
||||
addParticle(0, 192 + -32 * driftDir, 180, -5 * driftDir, totalFrameCount % 16 == 0 ? -1 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (hopStage != 0) {
|
||||
hopStage++;
|
||||
if (hopStage >= 15) {
|
||||
hopStage = 0;
|
||||
if (kartSteerAnim != targetAnim) {
|
||||
if (kartSteerAnim > targetAnim) {
|
||||
kartSteerAnim--;
|
||||
} else {
|
||||
kartSteerAnim++;
|
||||
}
|
||||
}
|
||||
|
||||
int animNo = abs_int(kartSteerAnim) / 2 + (jitter * 11);
|
||||
int animNo = abs_int(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 (totalFrameCount % 2 == 0) {
|
||||
|
@ -398,13 +390,21 @@ void main_loop() {
|
|||
if (kartSteerAnim >= 0) {
|
||||
// CopySpriteMasked(/*mksprites[kartSteerAnim / 2]*/sprite, (LCD_WIDTH_PX / 2) - 39, 128, 78, 81, 0x07e0);
|
||||
// CopySpriteMasked(mksprites[kartSteerAnim / 4], (LCD_WIDTH_PX / 2) - 36, 128, 72, 80, 0x4fe0);
|
||||
draw(imgs_kart[animNo], (LCD_WIDTH_PX / 2) - (96 / 2), 112 + jitter - (hopAnim[hopStage] * 3));
|
||||
draw(imgs_kart[animNo], (LCD_WIDTH_PX / 2) - (96 / 2), 112 + (jitter % 2) - (hopAnim[hopStage] * 3));
|
||||
if (newAnimNo != animNo) {
|
||||
draw(imgs_kart[newAnimNo], (LCD_WIDTH_PX / 2) - (96 / 2), 112 + (jitter % 2) - (hopAnim[hopStage] * 3));
|
||||
}
|
||||
} else {
|
||||
// CopySpriteMaskedFlipped(/*mksprites[-kartSteerAnim / 2]*/sprite, (LCD_WIDTH_PX / 2) - 39, 128, 78, 81, 0x07e0);
|
||||
// CopySpriteMaskedFlipped(mksprites[-kartSteerAnim / 4], (LCD_WIDTH_PX / 2) - 36, 128, 72, 80, 0x4fe0);
|
||||
draw_flipped(imgs_kart[animNo], (LCD_WIDTH_PX / 2) - (96 / 2), 112 + jitter - (hopAnim[hopStage] * 3));
|
||||
draw_flipped(imgs_kart[animNo], (LCD_WIDTH_PX / 2) - (96 / 2), 112 + (jitter % 2) - (hopAnim[hopStage] * 3));
|
||||
if (newAnimNo != animNo) {
|
||||
draw_flipped(imgs_kart[newAnimNo], (LCD_WIDTH_PX / 2) - (96 / 2), 112 + (jitter % 2) - (hopAnim[hopStage] * 3));
|
||||
}
|
||||
}
|
||||
|
||||
tickParticles();
|
||||
|
||||
Bdisp_PutDisp_DD_stripe(horizon + 2, LCD_HEIGHT_PX);
|
||||
|
||||
// draw_loop_x(img_loop, 0, 0, angle, LCD_WIDTH_PX);
|
||||
|
@ -413,7 +413,6 @@ void main_loop() {
|
|||
// Bdisp_PutDisp_DD();
|
||||
|
||||
totalFrameCount += 1;
|
||||
fpsCount++;
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
@ -425,9 +424,6 @@ int main() {
|
|||
|
||||
Bdisp_EnableColor(1);
|
||||
fillSky(0, LCD_HEIGHT_PX);
|
||||
#ifndef FXCG_MOCK
|
||||
lastTime = RTC_GetTicks();
|
||||
#endif
|
||||
|
||||
kart.x = 3565 / 12;
|
||||
kart.y = 2600 / 12;
|
||||
|
@ -443,6 +439,8 @@ int main() {
|
|||
kart.isTurningLeft = false;
|
||||
kart.isTurningRight = false;
|
||||
|
||||
initParticles();
|
||||
|
||||
#ifdef FXCG_MOCK
|
||||
#ifdef EMSCRIPTEN
|
||||
emscripten_set_main_loop(main_loop, 60, 1);
|
||||
|
|
|
@ -3,10 +3,15 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
|
||||
extern int totalFrameCount;
|
||||
|
||||
extern short angle;
|
||||
extern short xOffset;
|
||||
extern short yOffset;
|
||||
|
||||
extern bool drifting;
|
||||
extern int driftDir;
|
||||
|
||||
extern short index2;
|
||||
extern unsigned short element;
|
||||
|
||||
|
@ -18,4 +23,7 @@ int mod(int a, int b);
|
|||
float sin(int angle);
|
||||
float cos(int angle);
|
||||
|
||||
// TODO: Move into a separate file
|
||||
void fillSky(unsigned short yMin, unsigned short yMax);
|
||||
|
||||
#endif // _MAIN_H
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
#include "./particles.h"
|
||||
|
||||
#include "./sprites.h"
|
||||
#include "../data-headers/images.h"
|
||||
|
||||
#define MAX_PARTICLES 32
|
||||
|
||||
ParticleType types[] = {
|
||||
// Smoke
|
||||
{
|
||||
.maxAge = 12,
|
||||
.animLength = 3,
|
||||
.animDelay = 4,
|
||||
.animFrames = imgs_smoke
|
||||
}
|
||||
};
|
||||
|
||||
ParticleState particles[MAX_PARTICLES];
|
||||
|
||||
void initParticles() {
|
||||
for (int i = 0; i < MAX_PARTICLES; i++) {
|
||||
particles[i].age = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void tickParticles() {
|
||||
for (int i = 0; i < MAX_PARTICLES; i++) {
|
||||
ParticleState *particle = &particles[i];
|
||||
// Age < 0 means the particle is not active
|
||||
if (particle->age >= 0) {
|
||||
if (particle->age > types[particle->type].maxAge) {
|
||||
// Deactivate the particle
|
||||
particle->age = -1;
|
||||
continue;
|
||||
}
|
||||
particle->age++;
|
||||
particle->x += particle->xVel;
|
||||
particle->y += particle->yVel;
|
||||
// Draw the particle
|
||||
int frame = (particle->age / types[particle->type].animLength) % types[particle->type].animLength;
|
||||
draw(types[particle->type].animFrames[frame], particle->x, particle->y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addParticle(int type, int x, int y, int xVel, int yVel) {
|
||||
// Find the first free particle slot
|
||||
int slot = -1;
|
||||
for (int i = 0; i < MAX_PARTICLES; i++) {
|
||||
if (particles[i].age < 0) {
|
||||
slot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (slot < 0) {
|
||||
// No free particle slots
|
||||
return;
|
||||
}
|
||||
ParticleState *particle = &particles[slot];
|
||||
particle->type = type;
|
||||
particle->x = x;
|
||||
particle->y = y;
|
||||
particle->xVel = xVel;
|
||||
particle->yVel = yVel;
|
||||
particle->age = 0;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef _PARTICLES_H_
|
||||
#define _PARTICLES_H_
|
||||
|
||||
typedef struct {
|
||||
short type;
|
||||
short age;
|
||||
|
||||
short x;
|
||||
short y;
|
||||
|
||||
char xVel;
|
||||
char yVel;
|
||||
} ParticleState;
|
||||
|
||||
typedef struct {
|
||||
short maxAge;
|
||||
short animLength;
|
||||
char animDelay;
|
||||
const unsigned short** animFrames;
|
||||
} ParticleType;
|
||||
|
||||
void initParticles();
|
||||
void tickParticles();
|
||||
void addParticle(int type, int x, int y, int xVel, int yVel);
|
||||
|
||||
#endif // _PARTICLES_H_
|
|
@ -1,11 +1,14 @@
|
|||
#include "./physics.h"
|
||||
|
||||
#include "./main.h"
|
||||
#include "./maths.h"
|
||||
#include "./buttons.h"
|
||||
|
||||
#define angleWidth 192
|
||||
|
||||
// #define maxPower 0.075
|
||||
#define maxPower 0.125
|
||||
// #define maxPower 0.125
|
||||
#define maxPower 0.1
|
||||
#define maxReverse 0.0375
|
||||
#define powerFactor 0.001
|
||||
#define reverseFactor 0.0005
|
||||
|
@ -35,6 +38,10 @@ double fmax(double a, double b) {
|
|||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
double dmod(double a, double b) {
|
||||
return a - (int)(a / b) * b;
|
||||
}
|
||||
|
||||
void updateCar (Car *car) {
|
||||
if (car->isThrottling) {
|
||||
car->power += powerFactor * car->isThrottling;
|
||||
|
@ -52,12 +59,16 @@ void updateCar (Car *car) {
|
|||
|
||||
double direction = car->power > car->reverse ? 1 : -1;
|
||||
|
||||
if (car->isTurningLeft) {
|
||||
car->angularVelocity -= direction * turnSpeed * car->isTurningLeft;
|
||||
}
|
||||
if (car->isTurningRight) {
|
||||
car->angularVelocity += direction * turnSpeed * car->isTurningRight;
|
||||
double change = car->isTurningLeft ? -1 : car->isTurningRight ? 1 : 0;
|
||||
if (drifting) {
|
||||
if (driftDir == -1) {
|
||||
change += 0.7;
|
||||
} else {
|
||||
change -= 0.7;
|
||||
}
|
||||
}
|
||||
change *= direction * turnSpeed;
|
||||
car->angularVelocity += change;
|
||||
|
||||
car->xVelocity += sin2(car->angle) * (car->power - car->reverse);
|
||||
car->yVelocity += cos2(car->angle) * (car->power - car->reverse);
|
||||
|
@ -67,6 +78,7 @@ void updateCar (Car *car) {
|
|||
car->xVelocity *= drag;
|
||||
car->yVelocity *= drag;
|
||||
car->angle += car->angularVelocity;
|
||||
car->angle = dmod(car->angle, 3.1415926 * 2);
|
||||
car->angularVelocity *= angularDrag;
|
||||
}
|
||||
|
||||
|
@ -86,21 +98,23 @@ void updateCar (Car *car) {
|
|||
// isTurningRight: false,
|
||||
// };
|
||||
|
||||
void updateWithControls(Car *car, ControlState controls) {
|
||||
void updateWithControls(Car *car, ButtonState controls) {
|
||||
bool changed;
|
||||
|
||||
bool canTurn = car->power > 0.0025 || car->reverse;
|
||||
|
||||
double throttle = controls.up ? 1 : 0;
|
||||
double reverse = controls.down ? 1 : 0;
|
||||
double throttle = controls.accel ? 1 : 0;
|
||||
// double reverse = controls.down ? 1 : 0;
|
||||
double reverse = 0;
|
||||
|
||||
if (car->isThrottling != throttle || car->isReversing != reverse) {
|
||||
changed = true;
|
||||
car->isThrottling = throttle;
|
||||
car->isReversing = reverse;
|
||||
}
|
||||
bool turnLeft = canTurn && controls.left;
|
||||
bool turnRight = canTurn && controls.right;
|
||||
// Controls are reversed for now
|
||||
bool turnLeft = canTurn && /*controls.left*/ controls.right;
|
||||
bool turnRight = canTurn && /*controls.right*/ controls.left;
|
||||
|
||||
if (car->isTurningLeft != turnLeft) {
|
||||
changed = true;
|
||||
|
|
|
@ -3,12 +3,7 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
bool up;
|
||||
bool left;
|
||||
bool right;
|
||||
bool down;
|
||||
} ControlState;
|
||||
#include "./buttons.h"
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
|
@ -29,6 +24,6 @@ typedef struct {
|
|||
extern double drag;
|
||||
extern double turnSpeed;
|
||||
|
||||
void updateWithControls(Car *car, ControlState controls);
|
||||
void updateWithControls(Car *car, ButtonState controls);
|
||||
|
||||
#endif // _PHYSICS_H
|
||||
|
|
|
@ -83,38 +83,50 @@ void draw(const unsigned short* data, int x, int y) {
|
|||
// The height and width of the sprite are the first two elements in the data array
|
||||
int width = data[0];
|
||||
int height = data[1];
|
||||
// The data array starts at index 2
|
||||
const unsigned short* data2 = data + 2;
|
||||
// The offsets of the x and y positions are the third and fourth elements in the data array
|
||||
int xOffset = data[2];
|
||||
int yOffset = data[3];
|
||||
// The data array starts at index 4
|
||||
const unsigned short* data2 = data + 4;
|
||||
// Now draw the sprite
|
||||
CopySpriteMasked(data2, x, y, width, height, 0x4fe0);
|
||||
CopySpriteMasked(data2, x + xOffset, y + yOffset, width, height, 0x4fe0);
|
||||
}
|
||||
|
||||
void draw_alpha(const unsigned short* data, int x, int y, int alpha) {
|
||||
// The height and width of the sprite are the first two elements in the data array
|
||||
int width = data[0];
|
||||
int height = data[1];
|
||||
// The data array starts at index 2
|
||||
const unsigned short* data2 = data + 2;
|
||||
// The offsets of the x and y positions are the third and fourth elements in the data array
|
||||
int xOffset = data[2];
|
||||
int yOffset = data[3];
|
||||
// The data array starts at index 4
|
||||
const unsigned short* data2 = data + 4;
|
||||
// Now draw the sprite
|
||||
CopySpriteMaskedAlpha(data2, x, y, width, height, 0x4fe0, alpha);
|
||||
CopySpriteMaskedAlpha(data2, x + xOffset, y + yOffset, width, height, 0x4fe0, alpha);
|
||||
}
|
||||
|
||||
void draw_flipped(const unsigned short* data, int x, int y) {
|
||||
// The height and width of the sprite are the first two elements in the data array
|
||||
int width = data[0];
|
||||
int height = data[1];
|
||||
// The data array starts at index 2
|
||||
const unsigned short* data2 = data + 2;
|
||||
// The offsets of the x and y positions are the third and fourth elements in the data array
|
||||
int xOffset = data[2];
|
||||
int yOffset = data[3];
|
||||
// The data array starts at index 4
|
||||
const unsigned short* data2 = data + 4;
|
||||
// Now draw the sprite
|
||||
CopySpriteMaskedFlipped(data2, x, y, width, height, 0x4fe0);
|
||||
CopySpriteMaskedFlipped(data2, x + xOffset, y + yOffset, width, height, 0x4fe0);
|
||||
}
|
||||
|
||||
void draw_loop_x(const unsigned short* data, int x, int y, int xOffset, int drawWidth) {
|
||||
// The height and width of the sprite are the first two elements in the data array
|
||||
int width = data[0];
|
||||
int height = data[1];
|
||||
// The data array starts at index 2
|
||||
const unsigned short* data2 = data + 2;
|
||||
// The offsets of the x and y positions are the third and fourth elements in the data array
|
||||
int xOffset2 = data[2];
|
||||
int yOffset = data[3];
|
||||
// The data array starts at index 4
|
||||
const unsigned short* data2 = data + 4;
|
||||
// Now draw the sprite
|
||||
CopySpriteLoopX(data2, x, y, width, height, xOffset, drawWidth, 0x4fe0);
|
||||
CopySpriteLoopX(data2, x + xOffset2, y + yOffset, width, height, xOffset, drawWidth, 0x4fe0);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
unsigned char getTileType(short xPos, short yPos) {
|
||||
// __builtin_expect(xPos < 0 || xPos >= trackImageWidth || yPos < 0 || yPos >= trackImageHeight, 0);
|
||||
if (xPos < 0 || xPos >= trackImageWidth || yPos < 0 || yPos >= trackImageHeight) {
|
||||
if((unsigned short) xPos >= trackImageWidth || (unsigned short) yPos >= trackImageHeight) {
|
||||
return 0; // Grass
|
||||
} else {
|
||||
// Divide by 8
|
||||
|
|