mirror of
https://github.com/gbdk-2020/gbdk-2020.git
synced 2026-02-20 00:32:21 +01:00
Feature/text & dialogue example (#712)
Text and dialog examples by larold (Looks good, merging)
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -86,3 +86,8 @@ gbdk-lib/doc/
|
||||
|
||||
# VS.Code folder
|
||||
.vscode
|
||||
|
||||
gen/
|
||||
bin/
|
||||
obj/
|
||||
dist/
|
||||
@@ -0,0 +1,98 @@
|
||||
# If you move this project you can change the directory
|
||||
# to match your GBDK root directory (ex: GBDK_HOME = "C:/GBDK/"
|
||||
ifndef GBDK_HOME
|
||||
GBDK_HOME = ../../../
|
||||
endif
|
||||
|
||||
LCC = $(GBDK_HOME)bin/lcc
|
||||
PNG2ASSET = $(GBDK_HOME)bin/png2asset
|
||||
|
||||
# Set platforms to build here, spaced separated. (These are in the separate Makefile.targets)
|
||||
# They can also be built/cleaned individually: "make gg" and "make gg-clean"
|
||||
# Possible are: gb gbc pocket megaduck sms gg
|
||||
TARGETS=gb pocket megaduck sms gg nes
|
||||
|
||||
# Configure platform specific LCC flags here:
|
||||
LCCFLAGS_gb =
|
||||
LCCFLAGS_pocket =
|
||||
LCCFLAGS_duck =
|
||||
LCCFLAGS_gbc =
|
||||
LCCFLAGS_sms =
|
||||
LCCFLAGS_gg =
|
||||
LCCFLAGS_nes =
|
||||
|
||||
LCCFLAGS += $(LCCFLAGS_$(EXT)) # This adds the current platform specific LCC Flags
|
||||
|
||||
# GBDK_DEBUG = ON
|
||||
ifdef GBDK_DEBUG
|
||||
LCCFLAGS += -debug -v
|
||||
endif
|
||||
|
||||
|
||||
# You can set the name of the ROM file here
|
||||
PROJECTNAME = text_advanced_dialogue
|
||||
|
||||
SRCDIR = src
|
||||
OBJDIR = obj/$(EXT)
|
||||
RESDIR = res
|
||||
DISTDIR = dist
|
||||
BINDIR = build/$(EXT)
|
||||
GENDIR = gen/$(EXT)/src
|
||||
|
||||
MKDIRS = $(OBJDIR) $(BINDIR) $(GENDIR) # See bottom of Makefile for directory auto-creation
|
||||
GENSOURCES = $(foreach dir,$(GENDIR), $(wildcard $(dir)/*.c))
|
||||
BINS = $(OBJDIR)/$(PROJECTNAME).$(EXT)
|
||||
CSOURCES = $(foreach dir,$(SRCDIR),$(notdir $(wildcard $(dir)/*.c))) $(foreach dir,$(RESDIR),$(notdir $(wildcard $(dir)/*.c)))
|
||||
ASMSOURCES = $(foreach dir,$(SRCDIR),$(notdir $(wildcard $(dir)/*.s)))
|
||||
OBJS = $(CSOURCES:%.c=$(OBJDIR)/%.o) $(ASMSOURCES:%.s=$(OBJDIR)/%.o)
|
||||
|
||||
|
||||
# png2asset settings for backgrounds
|
||||
PNG2ASSET_BKG_SETTINGS_gg=-pack_mode sms -bpp 4
|
||||
PNG2ASSET_BKG_SETTINGS_sms=-pack_mode sms -bpp 4
|
||||
PNG2ASSET_BKG_SETTINGS_nes=-pack_mode nes -bpp 2
|
||||
PNG2ASSET_BKG_SETTINGS_gb=
|
||||
PNG2ASSET_BKG_SETTINGS_gbc=
|
||||
PNG2ASSET_BKG_SETTINGS_duck=
|
||||
PNG2ASSET_BKG_SETTINGS_pocket=
|
||||
|
||||
|
||||
# Builds all targets sequentially
|
||||
all: $(TARGETS)
|
||||
|
||||
# Compile .c files in "src/" to .o object files
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.c
|
||||
$(LCC) $(LCCFLAGS) $(CFLAGS) -I$(GENDIR) -c -o $@ $<
|
||||
|
||||
# Compile .s assembly files in "src/" to .o object files
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.s
|
||||
$(LCC) $(LCCFLAGS) $(CFLAGS) -I$(GENDIR) -c -o $@ $<
|
||||
|
||||
# If needed, compile .c files in "src/" to .s assembly files
|
||||
# (not required if .c is compiled directly to .o)
|
||||
$(OBJDIR)/%.s: $(SRCDIR)/%.c
|
||||
$(LCC) $(LCCFLAGS) $(CFLAGS) -I$(GENDIR) -S -o $@ $<
|
||||
|
||||
png2asset:
|
||||
$(PNG2ASSET) $(RESDIR)/Font.png $(PNG2ASSET_BKG_SETTINGS_$(EXT)) -c $(GENDIR)/Font.c -map -keep_palette_order -noflip
|
||||
$(PNG2ASSET) $(RESDIR)/DialogueBox.png $(PNG2ASSET_BKG_SETTINGS_$(EXT)) -c $(GENDIR)/DialogueBox.c -map -keep_palette_order -noflip
|
||||
|
||||
# Link the compiled object files into a .gb ROM file
|
||||
$(BINS): $(OBJS)
|
||||
$(LCC) $(LCCFLAGS) $(CFLAGS) -I$(GENDIR) -o $(BINDIR)/$(PROJECTNAME).$(EXT) $(OBJS) $(GENSOURCES)
|
||||
|
||||
clean:
|
||||
@echo Cleaning
|
||||
@for target in $(TARGETS); do \
|
||||
$(MAKE) $$target-clean; \
|
||||
done
|
||||
|
||||
# Include available build targets
|
||||
include Makefile.targets
|
||||
|
||||
|
||||
# create necessary directories after Makefile is parsed but before build
|
||||
# info prevents the command from being pasted into the makefile
|
||||
ifneq ($(strip $(EXT)),) # Only make the directories if EXT has been set by a target
|
||||
$(info $(shell mkdir -p $(MKDIRS)))
|
||||
endif
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
# Platform specific flags for compiling (only populate if they're both present)
|
||||
ifneq ($(strip $(PORT)),)
|
||||
ifneq ($(strip $(PLAT)),)
|
||||
CFLAGS += -m$(PORT):$(PLAT)
|
||||
endif
|
||||
endif
|
||||
|
||||
# Called by the individual targets below to build a ROM
|
||||
build-target: png2asset $(BINS)
|
||||
|
||||
clean-target:
|
||||
rm -rf $(OBJDIR)
|
||||
rm -rf $(BINDIR)
|
||||
|
||||
gb-clean:
|
||||
${MAKE} clean-target EXT=gb
|
||||
gb:
|
||||
${MAKE} build-target PORT=sm83 PLAT=gb EXT=gb
|
||||
|
||||
|
||||
gbc-clean:
|
||||
${MAKE} clean-target EXT=gbc
|
||||
gbc:
|
||||
${MAKE} build-target PORT=sm83 PLAT=gb EXT=gbc
|
||||
|
||||
|
||||
pocket-clean:
|
||||
${MAKE} clean-target EXT=pocket
|
||||
pocket:
|
||||
${MAKE} build-target PORT=sm83 PLAT=ap EXT=pocket
|
||||
|
||||
|
||||
megaduck-clean:
|
||||
${MAKE} clean-target EXT=duck
|
||||
megaduck:
|
||||
${MAKE} build-target PORT=sm83 PLAT=duck EXT=duck
|
||||
|
||||
|
||||
sms-clean:
|
||||
${MAKE} clean-target EXT=sms
|
||||
sms:
|
||||
${MAKE} build-target PORT=z80 PLAT=sms EXT=sms
|
||||
|
||||
|
||||
gg-clean:
|
||||
${MAKE} clean-target EXT=gg
|
||||
gg:
|
||||
${MAKE} build-target PORT=z80 PLAT=gg EXT=gg
|
||||
|
||||
|
||||
nes-clean:
|
||||
${MAKE} clean-target EXT=nes
|
||||
nes:
|
||||
${MAKE} build-target PORT=mos6502 PLAT=nes EXT=nes
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 165 B |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 483 B |
@@ -0,0 +1,375 @@
|
||||
#include <gbdk/platform.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "Font.h"
|
||||
#include "DialogueBox.h"
|
||||
|
||||
|
||||
#define MIN(A,B) ((A)<(B)?(A):(B))
|
||||
|
||||
#define TYPEWRITER_DELAY 2
|
||||
#define LINE_SKIP_DELAY 7
|
||||
#define LINE_SKIP 2
|
||||
#define DIALOG_BOX_HEIGHT 7
|
||||
#define DIALOG_BOX_INNER_HEIGHT (DIALOG_BOX_HEIGHT-2)
|
||||
|
||||
#if defined(SEGA)
|
||||
#define BYTES_PER_TILE 2
|
||||
#else
|
||||
#define BYTES_PER_TILE 1
|
||||
#endif
|
||||
|
||||
#if defined(SEGA) || defined(NINTENDO_NES)
|
||||
|
||||
#define get_winbkg_xy_addr get_bkg_xy_addr
|
||||
#define set_winbkg_based_tiles set_bkg_based_tiles
|
||||
#define set_text_tiles set_bkg_tiles
|
||||
#define fill_winbkg_rect fill_bkg_rect
|
||||
#define set_winbkg_tile_xy set_bkg_tile_xy
|
||||
#define DIALOGUE_BOX_Y (DEVICE_SCREEN_HEIGHT-DIALOG_BOX_HEIGHT)
|
||||
#else
|
||||
#define get_winbkg_xy_addr get_win_xy_addr
|
||||
#define set_winbkg_based_tiles set_win_based_tiles
|
||||
#define fill_winbkg_rect fill_win_rect
|
||||
#define set_winbkg_tile_xy set_win_tile_xy
|
||||
#define set_text_tiles set_win_tiles
|
||||
#define DIALOGUE_BOX_Y 0
|
||||
#endif
|
||||
|
||||
#define TILE_SIZE_BYTES (BYTES_PER_TILE*16)
|
||||
#define INNER_DIALOGUE_BOX_WIDTH (DEVICE_SCREEN_WIDTH-2)
|
||||
|
||||
int16_t windowYPosition=DEVICE_SCREEN_PX_HEIGHT;
|
||||
uint8_t fontTilesStart=0;
|
||||
|
||||
uint8_t joypadCurrent=0,joypadPrevious=0;
|
||||
|
||||
uint8_t loadedCharacters[Font_TILE_COUNT];
|
||||
uint8_t loadedCharacterCount=0;
|
||||
|
||||
void MoveWindow(void){
|
||||
|
||||
#if !defined(SEGA) && !defined(NINTENDO_NES)
|
||||
|
||||
move_win(7,windowYPosition);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
uint8_t GetTileForCharacter(char character) {
|
||||
|
||||
uint8_t vramTile=0;
|
||||
|
||||
|
||||
// Char's can be interpreted as integers
|
||||
// We don't need to map every alpha-numeric character
|
||||
// We can use basic math to simplify A-Z and 0-9
|
||||
if (character >= 'a' && character <= 'z') vramTile = (character - 'a') + 1;
|
||||
else if (character >= 'A' && character <= 'Z') vramTile = (character - 'A') + 1;
|
||||
else if (character >= '0' && character <= '9') vramTile = (character - '0') + 27;
|
||||
else {
|
||||
switch(character) {
|
||||
case '!': vramTile = 37; break;
|
||||
case ':': vramTile = 38; break;
|
||||
case '?': vramTile = 39; break;
|
||||
case '/': vramTile = 40; break;
|
||||
case '=': vramTile = 41; break;
|
||||
case ',': vramTile = 42; break;
|
||||
case '.': vramTile = 43; break;
|
||||
case '<': vramTile = 44; break;
|
||||
case '>': vramTile = 45; break;
|
||||
}
|
||||
}
|
||||
|
||||
return vramTile;
|
||||
|
||||
}
|
||||
|
||||
uint8_t IsAlphaNumeric(char character){
|
||||
|
||||
// Return true for a-z,A-Z, and 0-9
|
||||
if(character>='a'&&character<='z')return TRUE;
|
||||
else if(character>='A'&&character<='Z')return TRUE;
|
||||
else if(character>='0'&&character<='9')return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
uint8_t BreakLineEarly(uint16_t index, uint8_t columnSize, char* text){
|
||||
|
||||
char character = text[index++];
|
||||
|
||||
// We can break, if we are at the end of our row
|
||||
if(columnSize>=INNER_DIALOGUE_BOX_WIDTH)return TRUE;
|
||||
|
||||
// We DO NOT break on alpha-numeric characters
|
||||
if(IsAlphaNumeric(character))return FALSE;
|
||||
|
||||
// How many characters are left on the current line
|
||||
uint8_t spaceLeftOnLine=INNER_DIALOGUE_BOX_WIDTH-columnSize;
|
||||
uint8_t nextColumnSize=columnSize+1;
|
||||
|
||||
// Loop ahead until we reach the end of the string
|
||||
while((character=text[index++])!='\0'){
|
||||
|
||||
// Stop when we reach a non alphanumeric character
|
||||
if(!IsAlphaNumeric(character))break;
|
||||
|
||||
// Increase how many characters we've skipped
|
||||
nextColumnSize++;
|
||||
}
|
||||
|
||||
// Return TRUE if the distance to the next non alphanumeric character, is larger than we have left on the line
|
||||
return nextColumnSize>INNER_DIALOGUE_BOX_WIDTH;
|
||||
}
|
||||
|
||||
|
||||
void WaitForAButton(void){
|
||||
while(TRUE){
|
||||
|
||||
joypadPrevious=joypadCurrent;
|
||||
joypadCurrent = joypad();
|
||||
|
||||
if((joypadCurrent & J_A) && !(joypadPrevious & J_A))break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ClearDialogueBox(void){
|
||||
|
||||
// Fill the middle of the dialog box with blank space
|
||||
fill_winbkg_rect(1,DIALOGUE_BOX_Y+1,DEVICE_SCREEN_WIDTH-2,DIALOG_BOX_HEIGHT-2,0);
|
||||
|
||||
// Top and Bottom sides
|
||||
fill_winbkg_rect(1,DIALOGUE_BOX_Y,DEVICE_SCREEN_WIDTH-2,1,2);
|
||||
set_winbkg_tile_xy(DEVICE_SCREEN_WIDTH-1,DIALOGUE_BOX_Y+DIALOG_BOX_HEIGHT-1,6);
|
||||
fill_winbkg_rect(1,DIALOGUE_BOX_Y+DIALOG_BOX_HEIGHT-1,DEVICE_SCREEN_WIDTH-2,1,2);
|
||||
|
||||
// Left and right sides
|
||||
fill_winbkg_rect(0,DIALOGUE_BOX_Y+1,1,DIALOG_BOX_HEIGHT-2,4);
|
||||
fill_winbkg_rect(DEVICE_SCREEN_WIDTH-1,DIALOGUE_BOX_Y+1,1,DIALOG_BOX_HEIGHT-2,4);
|
||||
|
||||
// Top Left and Top Right corners
|
||||
set_winbkg_tile_xy(0,DIALOGUE_BOX_Y,1);
|
||||
set_winbkg_tile_xy(DEVICE_SCREEN_WIDTH-1,DIALOGUE_BOX_Y,3);
|
||||
|
||||
// Bottom Left and Bottom Right corners
|
||||
set_winbkg_tile_xy(0,DIALOGUE_BOX_Y+DIALOG_BOX_HEIGHT-1,5);
|
||||
set_winbkg_tile_xy(DEVICE_SCREEN_WIDTH-1,DIALOGUE_BOX_Y+DIALOG_BOX_HEIGHT-1,6);
|
||||
}
|
||||
|
||||
void ShowDialgoueBox(void){
|
||||
|
||||
ClearDialogueBox();
|
||||
|
||||
int16_t desiredWindowPosition = DEVICE_SCREEN_PX_HEIGHT - (DIALOG_BOX_HEIGHT*8);
|
||||
|
||||
while(windowYPosition>desiredWindowPosition){
|
||||
|
||||
windowYPosition-=4;
|
||||
MoveWindow();
|
||||
vsync();
|
||||
}
|
||||
}
|
||||
|
||||
void HideDialgoueBox(void){
|
||||
|
||||
int16_t desiredWindowPosition = DEVICE_SCREEN_PX_HEIGHT;
|
||||
|
||||
while(windowYPosition<desiredWindowPosition){
|
||||
|
||||
windowYPosition+=4;
|
||||
MoveWindow();
|
||||
vsync();
|
||||
}
|
||||
}
|
||||
|
||||
void ResetLoadedCharacters(void){
|
||||
|
||||
loadedCharacterCount=1;
|
||||
|
||||
// Reset everything to 255
|
||||
for(uint8_t i=0;i<45;i++)loadedCharacters[i]=255;
|
||||
}
|
||||
|
||||
void vsyncMultiple(uint8_t count){
|
||||
// Wait some frames
|
||||
// This creates a typewriter effect
|
||||
for(uint8_t i=0;i<count;i++){
|
||||
|
||||
vsync();
|
||||
}
|
||||
}
|
||||
|
||||
void DrawTextAdvanced(char* text){
|
||||
|
||||
uint8_t column=1;
|
||||
uint8_t row=DIALOGUE_BOX_Y+1;
|
||||
|
||||
ShowDialgoueBox();
|
||||
|
||||
ResetLoadedCharacters();
|
||||
|
||||
uint16_t index=0;
|
||||
uint8_t columnSize=0;
|
||||
uint8_t rowCount=0;
|
||||
|
||||
// Increase the first dimension by 1
|
||||
// So it's easy to slide up rows (the top values will always be 0)
|
||||
uint8_t copyBuffer[DIALOG_BOX_INNER_HEIGHT+1][INNER_DIALOGUE_BOX_WIDTH];
|
||||
uint8_t copyBufferCount=0;
|
||||
|
||||
// Clear the copy buffer
|
||||
for(uint8_t k=0;k<INNER_DIALOGUE_BOX_WIDTH;k++){
|
||||
for(uint8_t t=0;t<DIALOG_BOX_INNER_HEIGHT+1;t++){
|
||||
copyBuffer[t][k]=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get the address of the first tile in the row
|
||||
uint8_t* vramAddress = get_winbkg_xy_addr(column,row);
|
||||
|
||||
char c;
|
||||
|
||||
while((c=text[index])!='\0'){
|
||||
|
||||
uint8_t vramTile = GetTileForCharacter(c);
|
||||
|
||||
// If we haven't loaded this character into VRAM
|
||||
if(loadedCharacters[vramTile]==255){
|
||||
|
||||
// Save where we place this character in VRAM
|
||||
loadedCharacters[vramTile]=fontTilesStart+loadedCharacterCount++;
|
||||
|
||||
// Place this character in VRAM
|
||||
set_native_tile_data(loadedCharacters[vramTile],1,Font_tiles+vramTile*TILE_SIZE_BYTES);
|
||||
|
||||
}
|
||||
|
||||
// Draw our character at the address
|
||||
// THEN, increment the address
|
||||
set_vram_byte(vramAddress++,loadedCharacters[vramTile]);
|
||||
|
||||
#if defined(SEGA)
|
||||
set_vram_byte(vramAddress++,0);
|
||||
#endif
|
||||
|
||||
// Copy everything to a buffer
|
||||
// So we can easily slide that row upwards, without having to access VRAM
|
||||
if(rowCount<DIALOG_BOX_INNER_HEIGHT)copyBuffer[rowCount][copyBufferCount++] = loadedCharacters[vramTile];
|
||||
|
||||
index++;
|
||||
columnSize++;
|
||||
|
||||
// if we've reached the end of the row
|
||||
if(BreakLineEarly(index,columnSize,text) || c=='.'){
|
||||
|
||||
rowCount+=LINE_SKIP;
|
||||
|
||||
// Reset/Clear the copy buffer
|
||||
copyBufferCount=0;
|
||||
|
||||
// If we just drew a period or question mark,
|
||||
// wait for the a button and afterwards clear the dialogue box.
|
||||
if(c=='.'||c=='?'){
|
||||
WaitForAButton();
|
||||
ClearDialogueBox();
|
||||
rowCount=0;
|
||||
|
||||
// Clear the copy buffer
|
||||
for(uint8_t k=0;k<INNER_DIALOGUE_BOX_WIDTH;k++){
|
||||
for(uint8_t t=0;t<DIALOG_BOX_INNER_HEIGHT+1;t++){
|
||||
copyBuffer[t][k]=0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if we've drawn our rows
|
||||
else if( rowCount>=DIALOG_BOX_INNER_HEIGHT){
|
||||
|
||||
// We want the most recently drawn line to be at the top of the dialog box
|
||||
uint8_t shiftCount = rowCount-LINE_SKIP;
|
||||
|
||||
for(uint8_t k=0;k<shiftCount;k++){
|
||||
|
||||
for(uint8_t t=0;t<DIALOG_BOX_INNER_HEIGHT;t++){
|
||||
|
||||
uint8_t copyBufferIndex = MIN(1+t+k,DIALOG_BOX_INNER_HEIGHT);
|
||||
|
||||
set_text_tiles(1,DIALOGUE_BOX_Y+1+t,INNER_DIALOGUE_BOX_WIDTH,1,copyBuffer[copyBufferIndex]);
|
||||
}
|
||||
|
||||
// Wait a little bit
|
||||
vsyncMultiple(LINE_SKIP_DELAY);
|
||||
}
|
||||
|
||||
// Clear the copy buffer
|
||||
for(uint8_t k=0;k<INNER_DIALOGUE_BOX_WIDTH;k++){
|
||||
for(uint8_t t=0;t<DIALOG_BOX_INNER_HEIGHT;t++){
|
||||
copyBuffer[t][k]=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
rowCount=LINE_SKIP;
|
||||
|
||||
}
|
||||
|
||||
// reset for the next row
|
||||
vramAddress = get_winbkg_xy_addr(column,row+rowCount);
|
||||
|
||||
columnSize=0;
|
||||
|
||||
// If we just started a new line, skip spaces
|
||||
while(text[index]==' '){
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
vsyncMultiple(TYPEWRITER_DELAY);
|
||||
}
|
||||
|
||||
HideDialgoueBox();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ClearScreen(void){
|
||||
#if !defined(SEGA) && !defined(NINTENDO_NES)
|
||||
// Game Gear doesn't have a window.
|
||||
fill_win_rect(0,0,DEVICE_SCREEN_WIDTH,DEVICE_SCREEN_HEIGHT,0);
|
||||
#endif
|
||||
fill_bkg_rect(0,0,DEVICE_SCREEN_WIDTH,DEVICE_SCREEN_HEIGHT,0);
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
DISPLAY_ON;
|
||||
SHOW_BKG;
|
||||
|
||||
#if !defined(SEGA) && !defined(NINTENDO_NES)
|
||||
SHOW_WIN;
|
||||
#endif
|
||||
|
||||
fontTilesStart = DialogueBox_TILE_COUNT+1;
|
||||
uint8_t emptyTile[TILE_SIZE_BYTES];
|
||||
for(uint8_t i=0;i<TILE_SIZE_BYTES;i++)emptyTile[i]=0;
|
||||
|
||||
set_native_tile_data(0,1,emptyTile);
|
||||
|
||||
ClearScreen();
|
||||
|
||||
set_native_tile_data(1,DialogueBox_TILE_COUNT,DialogueBox_tiles);
|
||||
|
||||
while(TRUE){
|
||||
|
||||
// We'll pass in one long string, but the game will present to the player multiple pages.
|
||||
// By passing 3 as the final argument, the game boy will wait 3 frames between each character
|
||||
DrawTextAdvanced("When the code reaches a period or question mark, it will pause and wait for you to press the A button for it to continue. Afterwards, It will start a new page and continue. The code will automatically jump to a new line, when it cannot fully draw a word. When both rows of text are full, the code will slide the current text upwards and continue. For every page, the code will dynamically populate VRAM. Only letters and characters used, will be loaded into VRAM.");
|
||||
|
||||
}
|
||||
}
|
||||
105
gbdk-lib/examples/cross-platform/text_basic/Makefile
Normal file
105
gbdk-lib/examples/cross-platform/text_basic/Makefile
Normal file
@@ -0,0 +1,105 @@
|
||||
# If you move this project you can change the directory
|
||||
# to match your GBDK root directory (ex: GBDK_HOME = "C:/GBDK/"
|
||||
ifndef GBDK_HOME
|
||||
GBDK_HOME = ../../../
|
||||
endif
|
||||
|
||||
LCC = $(GBDK_HOME)bin/lcc
|
||||
PNG2ASSET = $(GBDK_HOME)bin/png2asset
|
||||
|
||||
# Set platforms to build here, spaced separated. (These are in the separate Makefile.targets)
|
||||
# They can also be built/cleaned individually: "make gg" and "make gg-clean"
|
||||
# Possible are: gb gbc pocket megaduck sms gg
|
||||
TARGETS=gb pocket megaduck sms gg nes
|
||||
|
||||
# Configure platform specific LCC flags here:
|
||||
LCCFLAGS_gb = -Wm-ys -Wl-yt0x1B -autobank # Set an MBC for banking (1B-ROM+MBC5+RAM+BATT)
|
||||
LCCFLAGS_pocket = -Wm-ys -Wl-yt0x1B -autobank # Usually the same as required for .gb
|
||||
LCCFLAGS_duck = -Wm-ys -Wl-yt0x1B -autobank # Usually the same as required for .gb
|
||||
LCCFLAGS_gbc = -Wm-ys -Wl-yt0x1B -Wm-yc -autobank # Same as .gb with: -Wm-yc (gb & gbc) or Wm-yC (gbc exclusive)
|
||||
LCCFLAGS_sms = -autobank
|
||||
LCCFLAGS_gg = -autobank
|
||||
LCCFLAGS_nes =
|
||||
|
||||
LCCFLAGS += $(LCCFLAGS_$(EXT)) # This adds the current platform specific LCC Flags
|
||||
|
||||
LCCFLAGS += -Wl-j -Wm-yoA -Wm-ya4 -Wb-ext=.rel -Wb-v # MBC + Autobanking related flags
|
||||
|
||||
# GBDK_DEBUG = ON
|
||||
ifdef GBDK_DEBUG
|
||||
LCCFLAGS += -debug -v
|
||||
endif
|
||||
|
||||
|
||||
# You can set the name of the ROM file here
|
||||
PROJECTNAME = text_basic
|
||||
|
||||
SRCDIR = src
|
||||
OBJDIR = obj/$(EXT)
|
||||
RESDIR = res
|
||||
DISTDIR = dist
|
||||
BINDIR = build/$(EXT)
|
||||
GENDIR = gen/$(EXT)/src
|
||||
|
||||
|
||||
MKDIRS = $(OBJDIR) $(BINDIR) $(GENDIR) # See bottom of Makefile for directory auto-creation
|
||||
GENSOURCES = $(foreach dir,$(GENDIR), $(wildcard $(dir)/*.c))
|
||||
BINS = $(OBJDIR)/$(PROJECTNAME).$(EXT)
|
||||
CSOURCES = $(foreach dir,$(SRCDIR),$(notdir $(wildcard $(dir)/*.c))) $(foreach dir,$(RESDIR),$(notdir $(wildcard $(dir)/*.c)))
|
||||
ASMSOURCES = $(foreach dir,$(SRCDIR),$(notdir $(wildcard $(dir)/*.s)))
|
||||
OBJS = $(CSOURCES:%.c=$(OBJDIR)/%.o) $(ASMSOURCES:%.s=$(OBJDIR)/%.o)
|
||||
|
||||
|
||||
# png2asset settings for backgrounds
|
||||
PNG2ASSET_BKG_SETTINGS_gg=-pack_mode sms -bpp 4
|
||||
PNG2ASSET_BKG_SETTINGS_sms=-pack_mode sms -bpp 4
|
||||
PNG2ASSET_BKG_SETTINGS_nes=-pack_mode nes -bpp 2
|
||||
PNG2ASSET_BKG_SETTINGS_gb=
|
||||
PNG2ASSET_BKG_SETTINGS_gbc=
|
||||
PNG2ASSET_BKG_SETTINGS_duck=
|
||||
PNG2ASSET_BKG_SETTINGS_pocket=
|
||||
|
||||
# Builds all targets sequentially
|
||||
all: $(TARGETS)
|
||||
|
||||
# Compile .c files in "src/" to .o object files
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.c
|
||||
$(LCC) $(LCCFLAGS) $(CFLAGS) -I$(GENDIR) -c -o $@ $<
|
||||
|
||||
# Compile .s assembly files in "src/" to .o object files
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.s
|
||||
$(LCC) $(LCCFLAGS) $(CFLAGS) -I$(GENDIR) -c -o $@ $<
|
||||
|
||||
# If needed, compile .c files in "src/" to .s assembly files
|
||||
# (not required if .c is compiled directly to .o)
|
||||
$(OBJDIR)/%.s: $(SRCDIR)/%.c
|
||||
$(LCC) $(LCCFLAGS) $(CFLAGS) -I$(GENDIR) -S -o $@ $<
|
||||
|
||||
|
||||
|
||||
|
||||
png2asset:
|
||||
$(PNG2ASSET) $(RESDIR)/Font.png $(PNG2ASSET_BKG_SETTINGS_$(EXT)) -c $(GENDIR)/Font.c -map -keep_palette_order -noflip
|
||||
|
||||
|
||||
# Link the compiled object files into a .gb ROM file
|
||||
$(BINS): $(OBJS)
|
||||
$(LCC) $(LCCFLAGS) $(CFLAGS) -I$(GENDIR) -o $(BINDIR)/$(PROJECTNAME).$(EXT) $(OBJS) $(GENSOURCES)
|
||||
|
||||
|
||||
|
||||
clean:
|
||||
@echo Cleaning
|
||||
@for target in $(TARGETS); do \
|
||||
$(MAKE) $$target-clean; \
|
||||
done
|
||||
|
||||
# Include available build targets
|
||||
include Makefile.targets
|
||||
|
||||
|
||||
# create necessary directories after Makefile is parsed but before build
|
||||
# info prevents the command from being pasted into the makefile
|
||||
ifneq ($(strip $(EXT)),) # Only make the directories if EXT has been set by a target
|
||||
$(info $(shell mkdir -p $(MKDIRS)))
|
||||
endif
|
||||
55
gbdk-lib/examples/cross-platform/text_basic/Makefile.targets
Normal file
55
gbdk-lib/examples/cross-platform/text_basic/Makefile.targets
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
# Platform specific flags for compiling (only populate if they're both present)
|
||||
ifneq ($(strip $(PORT)),)
|
||||
ifneq ($(strip $(PLAT)),)
|
||||
CFLAGS += -m$(PORT):$(PLAT)
|
||||
endif
|
||||
endif
|
||||
|
||||
# Called by the individual targets below to build a ROM
|
||||
build-target: png2asset $(BINS)
|
||||
|
||||
clean-target:
|
||||
rm -rf $(OBJDIR)
|
||||
rm -rf $(BINDIR)
|
||||
|
||||
gb-clean:
|
||||
${MAKE} clean-target EXT=gb
|
||||
gb:
|
||||
${MAKE} build-target PORT=sm83 PLAT=gb EXT=gb
|
||||
|
||||
|
||||
gbc-clean:
|
||||
${MAKE} clean-target EXT=gbc
|
||||
gbc:
|
||||
${MAKE} build-target PORT=sm83 PLAT=gb EXT=gbc
|
||||
|
||||
|
||||
pocket-clean:
|
||||
${MAKE} clean-target EXT=pocket
|
||||
pocket:
|
||||
${MAKE} build-target PORT=sm83 PLAT=ap EXT=pocket
|
||||
|
||||
|
||||
megaduck-clean:
|
||||
${MAKE} clean-target EXT=duck
|
||||
megaduck:
|
||||
${MAKE} build-target PORT=sm83 PLAT=duck EXT=duck
|
||||
|
||||
|
||||
sms-clean:
|
||||
${MAKE} clean-target EXT=sms
|
||||
sms:
|
||||
${MAKE} build-target PORT=z80 PLAT=sms EXT=sms
|
||||
|
||||
|
||||
gg-clean:
|
||||
${MAKE} clean-target EXT=gg
|
||||
gg:
|
||||
${MAKE} build-target PORT=z80 PLAT=gg EXT=gg
|
||||
|
||||
|
||||
nes-clean:
|
||||
${MAKE} clean-target EXT=nes
|
||||
nes:
|
||||
${MAKE} build-target PORT=mos6502 PLAT=nes EXT=nes
|
||||
BIN
gbdk-lib/examples/cross-platform/text_basic/res/Font.aseprite
Normal file
BIN
gbdk-lib/examples/cross-platform/text_basic/res/Font.aseprite
Normal file
Binary file not shown.
BIN
gbdk-lib/examples/cross-platform/text_basic/res/Font.png
Normal file
BIN
gbdk-lib/examples/cross-platform/text_basic/res/Font.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 483 B |
71
gbdk-lib/examples/cross-platform/text_basic/src/main.c
Normal file
71
gbdk-lib/examples/cross-platform/text_basic/src/main.c
Normal file
@@ -0,0 +1,71 @@
|
||||
#include <gbdk/platform.h>
|
||||
#include <stdint.h>
|
||||
#include "Font.h"
|
||||
|
||||
|
||||
uint8_t GetCharacterVRamTile(char character) {
|
||||
|
||||
uint8_t vramTile=0;
|
||||
|
||||
|
||||
// Char's can be interpreted as integers
|
||||
// We don't need to map every alpha-numeric character
|
||||
// We can use basic math to simplify A-Z and 0-9
|
||||
if (character >= 'a' && character <= 'z') vramTile = (character - 'a') + 1;
|
||||
else if (character >= 'A' && character <= 'Z') vramTile = (character - 'A') + 1;
|
||||
else if (character >= '0' && character <= '9') vramTile = (character - '0') + 27;
|
||||
else {
|
||||
switch(character) {
|
||||
case '!': vramTile = 37; break;
|
||||
case ':': vramTile = 38; break;
|
||||
case '?': vramTile = 39; break;
|
||||
case '/': vramTile = 40; break;
|
||||
case '=': vramTile = 41; break;
|
||||
case ',': vramTile = 42; break;
|
||||
case '.': vramTile = 43; break;
|
||||
case '<': vramTile = 44; break;
|
||||
case '>': vramTile = 45; break;
|
||||
}
|
||||
}
|
||||
|
||||
return vramTile;
|
||||
|
||||
}
|
||||
|
||||
void DrawText(uint8_t column, uint8_t row, char* text){
|
||||
|
||||
// Get the address of the first tile in the row
|
||||
uint8_t* vramAddress = get_bkg_xy_addr(column,row);
|
||||
|
||||
uint16_t index=0;
|
||||
|
||||
while(text[index]!='\0'){
|
||||
|
||||
char character = text[index];
|
||||
|
||||
// Draw our character at the address
|
||||
// THEN, increment the address
|
||||
uint8_t vramTile = GetCharacterVRamTile(character);
|
||||
|
||||
set_vram_byte(vramAddress++,vramTile);
|
||||
|
||||
#if defined(SEGA)
|
||||
set_vram_byte(vramAddress++,0);
|
||||
#endif
|
||||
|
||||
index++;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
SHOW_BKG;
|
||||
|
||||
set_native_tile_data(0,Font_TILE_COUNT,Font_tiles);
|
||||
|
||||
fill_bkg_rect(0,0,DEVICE_SCREEN_WIDTH,DEVICE_SCREEN_HEIGHT,0);
|
||||
|
||||
// We'll pass zero for the final argument, to draw the text instantly
|
||||
DrawText(1,1,"GBDK Text Example");
|
||||
}
|
||||
102
gbdk-lib/examples/cross-platform/text_typewriter/Makefile
Normal file
102
gbdk-lib/examples/cross-platform/text_typewriter/Makefile
Normal file
@@ -0,0 +1,102 @@
|
||||
# If you move this project you can change the directory
|
||||
# to match your GBDK root directory (ex: GBDK_HOME = "C:/GBDK/"
|
||||
ifndef GBDK_HOME
|
||||
GBDK_HOME = ../../../
|
||||
endif
|
||||
|
||||
LCC = $(GBDK_HOME)bin/lcc
|
||||
PNG2ASSET = $(GBDK_HOME)bin/png2asset
|
||||
|
||||
# Set platforms to build here, spaced separated. (These are in the separate Makefile.targets)
|
||||
# They can also be built/cleaned individually: "make gg" and "make gg-clean"
|
||||
# Possible are: gb gbc pocket megaduck sms gg
|
||||
TARGETS=gb pocket megaduck sms gg nes
|
||||
|
||||
# Configure platform specific LCC flags here:
|
||||
LCCFLAGS_gb = -Wm-ys -Wl-yt0x1B -autobank # Set an MBC for banking (1B-ROM+MBC5+RAM+BATT)
|
||||
LCCFLAGS_pocket = -Wm-ys -Wl-yt0x1B -autobank # Usually the same as required for .gb
|
||||
LCCFLAGS_duck = -Wm-ys -Wl-yt0x1B -autobank # Usually the same as required for .gb
|
||||
LCCFLAGS_gbc = -Wm-ys -Wl-yt0x1B -Wm-yc -autobank # Same as .gb with: -Wm-yc (gb & gbc) or Wm-yC (gbc exclusive)
|
||||
LCCFLAGS_sms = -autobank
|
||||
LCCFLAGS_gg = -autobank
|
||||
LCCFLAGS_nes =
|
||||
|
||||
LCCFLAGS += $(LCCFLAGS_$(EXT)) # This adds the current platform specific LCC Flags
|
||||
|
||||
LCCFLAGS += -Wl-j -Wm-yoA -Wm-ya4 -Wb-ext=.rel -Wb-v # MBC + Autobanking related flags
|
||||
|
||||
# GBDK_DEBUG = ON
|
||||
ifdef GBDK_DEBUG
|
||||
LCCFLAGS += -debug -v
|
||||
endif
|
||||
|
||||
|
||||
# You can set the name of the ROM file here
|
||||
PROJECTNAME = text_typewriter
|
||||
|
||||
SRCDIR = src
|
||||
OBJDIR = obj/$(EXT)
|
||||
RESDIR = res
|
||||
DISTDIR = dist
|
||||
BINDIR = build/$(EXT)
|
||||
GENDIR = gen/$(EXT)/src
|
||||
|
||||
MKDIRS = $(OBJDIR) $(BINDIR) $(GENDIR) # See bottom of Makefile for directory auto-creation
|
||||
BINS = $(OBJDIR)/$(PROJECTNAME).$(EXT)
|
||||
|
||||
GENSOURCES = $(foreach dir,$(GENDIR), $(wildcard $(dir)/*.c))
|
||||
CSOURCES = $(foreach dir,$(SRCDIR),$(notdir $(wildcard $(dir)/*.c))) $(foreach dir,$(RESDIR),$(notdir $(wildcard $(dir)/*.c)))
|
||||
ASMSOURCES = $(foreach dir,$(SRCDIR),$(notdir $(wildcard $(dir)/*.s)))
|
||||
OBJS = $(CSOURCES:%.c=$(OBJDIR)/%.o) $(ASMSOURCES:%.s=$(OBJDIR)/%.o)
|
||||
|
||||
|
||||
# png2asset settings for backgrounds
|
||||
PNG2ASSET_BKG_SETTINGS_gg=-pack_mode sms -bpp 4
|
||||
PNG2ASSET_BKG_SETTINGS_sms=-pack_mode sms -bpp 4
|
||||
PNG2ASSET_BKG_SETTINGS_nes=-pack_mode nes -bpp 2
|
||||
PNG2ASSET_BKG_SETTINGS_gb=
|
||||
PNG2ASSET_BKG_SETTINGS_gbc=
|
||||
PNG2ASSET_BKG_SETTINGS_duck=
|
||||
PNG2ASSET_BKG_SETTINGS_pocket=
|
||||
|
||||
# Builds all targets sequentially
|
||||
all: $(TARGETS)
|
||||
|
||||
# Compile .c files in "src/" to .o object files
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.c
|
||||
$(LCC) $(LCCFLAGS) $(CFLAGS) -I$(GENDIR) -c -o $@ $<
|
||||
|
||||
# Compile .s assembly files in "src/" to .o object files
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.s
|
||||
$(LCC) $(LCCFLAGS) $(CFLAGS) -I$(GENDIR) -c -o $@ $<
|
||||
|
||||
# If needed, compile .c files in "src/" to .s assembly files
|
||||
# (not required if .c is compiled directly to .o)
|
||||
$(OBJDIR)/%.s: $(SRCDIR)/%.c
|
||||
$(LCC) $(LCCFLAGS) $(CFLAGS) -I$(GENDIR) -S -o $@ $<
|
||||
|
||||
|
||||
png2asset:
|
||||
$(PNG2ASSET) $(RESDIR)/Font.png $(PNG2ASSET_BKG_SETTINGS_$(EXT)) -c $(GENDIR)/Font.c -map -keep_palette_order -noflip
|
||||
|
||||
|
||||
# Link the compiled object files into a .gb ROM file
|
||||
$(BINS): $(OBJS)
|
||||
$(LCC) $(LCCFLAGS) $(CFLAGS) -I$(GENDIR) -o $(BINDIR)/$(PROJECTNAME).$(EXT) $(OBJS) $(GENSOURCES)
|
||||
|
||||
|
||||
clean:
|
||||
@echo Cleaning
|
||||
@for target in $(TARGETS); do \
|
||||
$(MAKE) $$target-clean; \
|
||||
done
|
||||
|
||||
# Include available build targets
|
||||
include Makefile.targets
|
||||
|
||||
|
||||
# create necessary directories after Makefile is parsed but before build
|
||||
# info prevents the command from being pasted into the makefile
|
||||
ifneq ($(strip $(EXT)),) # Only make the directories if EXT has been set by a target
|
||||
$(info $(shell mkdir -p $(MKDIRS)))
|
||||
endif
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
# Platform specific flags for compiling (only populate if they're both present)
|
||||
ifneq ($(strip $(PORT)),)
|
||||
ifneq ($(strip $(PLAT)),)
|
||||
CFLAGS += -m$(PORT):$(PLAT)
|
||||
endif
|
||||
endif
|
||||
|
||||
# Called by the individual targets below to build a ROM
|
||||
build-target: png2asset $(BINS)
|
||||
|
||||
clean-target:
|
||||
rm -rf $(OBJDIR)
|
||||
rm -rf $(BINDIR)
|
||||
|
||||
gb-clean:
|
||||
${MAKE} clean-target EXT=gb
|
||||
gb:
|
||||
${MAKE} build-target PORT=sm83 PLAT=gb EXT=gb
|
||||
|
||||
|
||||
gbc-clean:
|
||||
${MAKE} clean-target EXT=gbc
|
||||
gbc:
|
||||
${MAKE} build-target PORT=sm83 PLAT=gb EXT=gbc
|
||||
|
||||
|
||||
pocket-clean:
|
||||
${MAKE} clean-target EXT=pocket
|
||||
pocket:
|
||||
${MAKE} build-target PORT=sm83 PLAT=ap EXT=pocket
|
||||
|
||||
|
||||
megaduck-clean:
|
||||
${MAKE} clean-target EXT=duck
|
||||
megaduck:
|
||||
${MAKE} build-target PORT=sm83 PLAT=duck EXT=duck
|
||||
|
||||
|
||||
sms-clean:
|
||||
${MAKE} clean-target EXT=sms
|
||||
sms:
|
||||
${MAKE} build-target PORT=z80 PLAT=sms EXT=sms
|
||||
|
||||
|
||||
gg-clean:
|
||||
${MAKE} clean-target EXT=gg
|
||||
gg:
|
||||
${MAKE} build-target PORT=z80 PLAT=gg EXT=gg
|
||||
|
||||
|
||||
nes-clean:
|
||||
${MAKE} clean-target EXT=nes
|
||||
nes:
|
||||
${MAKE} build-target PORT=mos6502 PLAT=nes EXT=nes
|
||||
Binary file not shown.
BIN
gbdk-lib/examples/cross-platform/text_typewriter/res/Font.png
Normal file
BIN
gbdk-lib/examples/cross-platform/text_typewriter/res/Font.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 483 B |
95
gbdk-lib/examples/cross-platform/text_typewriter/src/main.c
Normal file
95
gbdk-lib/examples/cross-platform/text_typewriter/src/main.c
Normal file
@@ -0,0 +1,95 @@
|
||||
#include <gbdk/platform.h>
|
||||
#include <stdint.h>
|
||||
#include "Font.h"
|
||||
|
||||
#define THREE_FRAMES 3
|
||||
|
||||
uint8_t GetCharacterVRamTile(char character) {
|
||||
|
||||
uint8_t vramTile=0;
|
||||
|
||||
|
||||
// Char's can be interpreted as integers
|
||||
// We don't need to map every alpha-numeric character
|
||||
// We can use basic math to simplify A-Z and 0-9
|
||||
if (character >= 'a' && character <= 'z') vramTile = (character - 'a') + 1;
|
||||
else if (character >= 'A' && character <= 'Z') vramTile = (character - 'A') + 1;
|
||||
else if (character >= '0' && character <= '9') vramTile = (character - '0') + 27;
|
||||
else {
|
||||
switch(character) {
|
||||
case '!': vramTile = 37; break;
|
||||
case ':': vramTile = 38; break;
|
||||
case '?': vramTile = 39; break;
|
||||
case '/': vramTile = 40; break;
|
||||
case '=': vramTile = 41; break;
|
||||
case ',': vramTile = 42; break;
|
||||
case '.': vramTile = 43; break;
|
||||
case '<': vramTile = 44; break;
|
||||
case '>': vramTile = 45; break;
|
||||
}
|
||||
}
|
||||
|
||||
return vramTile;
|
||||
|
||||
}
|
||||
|
||||
void DrawText( char* text,uint8_t typewriterDelay){
|
||||
|
||||
uint8_t column = 0;
|
||||
uint8_t row = 0;
|
||||
|
||||
// Get the address of the first tile in the row
|
||||
uint8_t* vramAddress = get_bkg_xy_addr(column,row);
|
||||
|
||||
uint16_t index=0;
|
||||
uint8_t columnIndex=0;
|
||||
|
||||
while(text[index]!='\0'){
|
||||
|
||||
char character = text[index];
|
||||
|
||||
// Get the vram tile to draw
|
||||
uint8_t vramTile = GetCharacterVRamTile(character);
|
||||
|
||||
set_vram_byte(vramAddress++,vramTile);
|
||||
|
||||
#if defined(SEGA)
|
||||
set_vram_byte(vramAddress++,0);
|
||||
#endif
|
||||
|
||||
index++;
|
||||
columnIndex++;
|
||||
|
||||
// if we've reached the end of the row
|
||||
if(columnIndex>=DEVICE_SCREEN_WIDTH){
|
||||
|
||||
// reset for the next row
|
||||
vramAddress = get_bkg_xy_addr(column,++row);
|
||||
|
||||
columnIndex=0;
|
||||
}
|
||||
|
||||
if(typewriterDelay>0){
|
||||
|
||||
// Wait some frames
|
||||
// This creats a typewriter effect
|
||||
for(uint8_t i=0;i<typewriterDelay;i++){
|
||||
|
||||
vsync();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
SHOW_BKG;
|
||||
|
||||
set_native_tile_data(0,Font_TILE_COUNT,Font_tiles);
|
||||
|
||||
fill_bkg_rect(0,0,DEVICE_SCREEN_WIDTH,DEVICE_SCREEN_HEIGHT,0);
|
||||
|
||||
// By passing 3 as the final argument, the game boy will wait 3 frames between each character
|
||||
DrawText("his is a way to draw text on the screen in GBDK. The code will automatically jump to a new line, when it reaches the end of the row.",THREE_FRAMES);
|
||||
}
|
||||
Reference in New Issue
Block a user