mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-22 16:33:48 +00:00
Added NES balls example.
This commit is contained in:
parent
81b638f060
commit
79484c4b37
161
src/test/kc/complex/nes-balls/kickballs-2.c
Normal file
161
src/test/kc/complex/nes-balls/kickballs-2.c
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
#pragma target(nes)
|
||||||
|
#pragma emulator("java -jar /Applications/Nintaco_bin_2020-05-01/Nintaco.jar")
|
||||||
|
#include <nes.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define MAX_BALLS 50
|
||||||
|
#define WEIGHT 0x0010
|
||||||
|
#define RELEASE_TIMER 0x09
|
||||||
|
|
||||||
|
#define poke(addr) (*(unsigned byte *)(addr))
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned short x_position;
|
||||||
|
unsigned short y_position;
|
||||||
|
unsigned short x_velocity;
|
||||||
|
unsigned short y_velocity;
|
||||||
|
} ball;
|
||||||
|
|
||||||
|
#pragma data_seg(GameRam)
|
||||||
|
// Moving balls (in GameRAM)
|
||||||
|
ball balls[64];
|
||||||
|
|
||||||
|
#pragma data_seg(Data)
|
||||||
|
|
||||||
|
static const unsigned char sine_table[256] = {
|
||||||
|
0x40,0x42,0x43,0x45,0x46,0x48,0x49,0x4b,0x4c,0x4e,0x50,0x51,0x53,0x54,0x56,0x57,
|
||||||
|
0x58,0x5a,0x5b,0x5d,0x5e,0x60,0x61,0x62,0x64,0x65,0x66,0x67,0x69,0x6a,0x6b,0x6c,
|
||||||
|
0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x78,0x79,0x7a,0x7b,
|
||||||
|
0x7b,0x7c,0x7c,0x7d,0x7d,0x7e,0x7e,0x7e,0x7f,0x7f,0x7f,0x80,0x80,0x80,0x80,0x80,
|
||||||
|
0x80,0x80,0x80,0x80,0x80,0x80,0x7f,0x7f,0x7f,0x7e,0x7e,0x7e,0x7d,0x7d,0x7c,0x7c,
|
||||||
|
0x7b,0x7b,0x7a,0x79,0x78,0x78,0x77,0x76,0x75,0x74,0x73,0x72,0x71,0x70,0x6f,0x6e,
|
||||||
|
0x6d,0x6c,0x6b,0x6a,0x69,0x67,0x66,0x65,0x64,0x62,0x61,0x60,0x5e,0x5d,0x5b,0x5a,
|
||||||
|
0x58,0x57,0x56,0x54,0x53,0x51,0x50,0x4e,0x4c,0x4b,0x49,0x48,0x46,0x45,0x43,0x42,
|
||||||
|
0x40,0x3e,0x3d,0x3b,0x3a,0x38,0x37,0x35,0x34,0x32,0x30,0x2f,0x2d,0x2c,0x2a,0x29,
|
||||||
|
0x28,0x26,0x25,0x23,0x22,0x20,0x1f,0x1e,0x1c,0x1b,0x1a,0x19,0x17,0x16,0x15,0x14,
|
||||||
|
0x13,0x12,0x11,0x10,0xf,0xe,0xd,0xc,0xb,0xa,0x9,0x8,0x8,0x7,0x6,0x5,
|
||||||
|
0x5,0x4,0x4,0x3,0x3,0x2,0x2,0x2,0x1,0x1,0x1,0x0,0x0,0x0,0x0,0x0,
|
||||||
|
0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x1,0x2,0x2,0x2,0x3,0x3,0x4,0x4,
|
||||||
|
0x5,0x5,0x6,0x7,0x8,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,0x10,0x11,0x12,
|
||||||
|
0x13,0x14,0x15,0x16,0x17,0x19,0x1a,0x1b,0x1c,0x1e,0x1f,0x20,0x22,0x23,0x25,0x26,
|
||||||
|
0x28,0x29,0x2a,0x2c,0x2d,0x2f,0x30,0x32,0x34,0x35,0x37,0x38,0x3a,0x3b,0x3d,0x3e
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned char object[5] = { 0, 0, 10, 3, 128 };
|
||||||
|
|
||||||
|
const unsigned char palette[] = { 0x34,0x24,0x14,0x04, 0x34,0x24,0x14,0x04, 0x34,0x24,0x14,0x04, 0x34,0x24,0x14,0x04, 0x34,0x24,0x14,0x04, 0x34,0x24,0x14,0x04, 0x34,0x24,0x14,0x04, 0x34,0x24,0x14,0x04 };
|
||||||
|
|
||||||
|
const unsigned char h_bar_tilemap[] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 };
|
||||||
|
|
||||||
|
volatile unsigned char scroll_y = 0;
|
||||||
|
volatile unsigned char vblank_hit = 0;
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
// Initialize NES after RESET
|
||||||
|
initNES();
|
||||||
|
// Transfer the palette
|
||||||
|
ppuDataTransfer(PPU_PALETTE, palette, sizeof(palette));
|
||||||
|
// Fill the PPU attribute table
|
||||||
|
ppuDataFill(PPU_NAME_TABLE_0, 0, 32*30);
|
||||||
|
ppuDataFill(PPU_ATTRIBUTE_TABLE_0, 0, 0x40);
|
||||||
|
ppuDataTransfer(0x2040, h_bar_tilemap, sizeof(h_bar_tilemap));
|
||||||
|
// Enable screen rendering and vblank
|
||||||
|
enableVideoOutput();
|
||||||
|
// Enable vertical blank interrupt, select sprite pattern table 1
|
||||||
|
PPU->PPUCTRL = 0b10001000;
|
||||||
|
|
||||||
|
unsigned int i;
|
||||||
|
unsigned char active_balls = 0;
|
||||||
|
unsigned char timer = 0;
|
||||||
|
unsigned char timer_2 = 0;
|
||||||
|
unsigned char h_bar = 0x80;
|
||||||
|
unsigned char sprite_idx = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_BALLS; i++)
|
||||||
|
{
|
||||||
|
balls[i].x_velocity = rand() & 0x3FF;
|
||||||
|
balls[i].y_velocity = rand() & 0x0FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
timer_2++;
|
||||||
|
h_bar = sine_table[timer_2] + 0x60;
|
||||||
|
scroll_y = h_bar ^ 0xFF;
|
||||||
|
|
||||||
|
if (active_balls < MAX_BALLS)
|
||||||
|
{
|
||||||
|
if (timer++ == RELEASE_TIMER)
|
||||||
|
{
|
||||||
|
timer = 0;
|
||||||
|
active_balls++;
|
||||||
|
balls[active_balls].x_position = 0;
|
||||||
|
balls[active_balls].y_position = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sprite_idx = 0;
|
||||||
|
for (i = 0; i < active_balls; i++)
|
||||||
|
{
|
||||||
|
balls[i].x_position += balls[i].x_velocity;
|
||||||
|
balls[i].y_position += (balls[i].y_velocity += WEIGHT);
|
||||||
|
|
||||||
|
if ((balls[i].x_position >> 8) < 8)
|
||||||
|
{
|
||||||
|
balls[i].x_velocity ^= 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((balls[i].y_position >> 8) >= h_bar) && (balls[i].y_position >> 8) < h_bar + 8)
|
||||||
|
{
|
||||||
|
balls[i].y_velocity ^= 0xFFFF;
|
||||||
|
balls[i].y_position = ((unsigned short)(h_bar - 2) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPRITE_BUFFER[sprite_idx].y = (unsigned char) (balls[i].y_position >> 8);
|
||||||
|
SPRITE_BUFFER[sprite_idx].tile = 0x0a;
|
||||||
|
SPRITE_BUFFER[sprite_idx].attributes = 3;
|
||||||
|
SPRITE_BUFFER[sprite_idx].x = (unsigned char) (balls[i].x_position >> 8);
|
||||||
|
sprite_idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
poke(0x2001) = 0x98;
|
||||||
|
while (!vblank_hit); // wait for vblank
|
||||||
|
vblank_hit = 0;
|
||||||
|
poke(0x2001) = 0x18;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NMI Called when the PPU refreshes the screen (also known as the V-Blank period)
|
||||||
|
interrupt(hardware_stack) void vblank() {
|
||||||
|
// Set scroll
|
||||||
|
PPU->PPUSCROLL = 0;
|
||||||
|
PPU->PPUSCROLL = scroll_y;
|
||||||
|
// DMA transfer the entire sprite buffer to the PPU
|
||||||
|
ppuSpriteBufferDmaTransfer(SPRITE_BUFFER);
|
||||||
|
vblank_hit++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tile Set (in CHR ROM)
|
||||||
|
#pragma data_seg(Tiles)
|
||||||
|
export char TILES[] = kickasm(resource "lazydata.chr") {{
|
||||||
|
.import binary "lazydata.chr"
|
||||||
|
}};
|
||||||
|
|
||||||
|
// Sprite Buffer (in GAME RAM)
|
||||||
|
// Will be transferred to the PPU via DMA during vblank
|
||||||
|
#pragma data_seg(GameRam)
|
||||||
|
struct SpriteData align(0x100) SPRITE_BUFFER[0x100];
|
||||||
|
|
||||||
|
// Interrupt Vectors (in PRG ROM)
|
||||||
|
#pragma data_seg(Vectors)
|
||||||
|
export void()* const VECTORS[] = {
|
||||||
|
// NMI Called when the PPU refreshes the screen (also known as the V-Blank period)
|
||||||
|
&vblank,
|
||||||
|
// RESET Called when the NES is reset, including when it is turned on.
|
||||||
|
&main,
|
||||||
|
// IRQ Called when a BRK instruction is executed.
|
||||||
|
0
|
||||||
|
};
|
BIN
src/test/kc/complex/nes-balls/lazydata.chr
Normal file
BIN
src/test/kc/complex/nes-balls/lazydata.chr
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user