// foreground #define FG_I 576 #define FG_W 64 #define OBSTACLE_COUNT 24 #define FG_SPEED FIX16(1.75) #define FG_SPEED_NORM FIX16(1.75 * 0.707) struct obstacle { bool active, top; Vect2D_f16 pos, size; s16 startX; }; struct obstacle obstacles[OBSTACLE_COUNT]; s16 currentFg; SpriteDefinition* currentTopImage; SpriteDefinition* currentBottomImage; // draw #define CEIL_Y 3 #define FLOOR_Y 24 static void drawFg(){ switch(currentFg){ case 0: currentTopImage = &rock1Top; currentBottomImage = &rock1Bottom; break; case 1: currentTopImage = &rock2Top; currentBottomImage = &rock2Bottom; break; } for(u16 x = 0; x < FG_W; x++){ if(x % 4 == 0){ VDP_drawImageEx(BG_B, currentTopImage, TILE_ATTR_FULL(PAL2, 1, 0, 0, FG_I), x, CEIL_Y, 0, DMA); VDP_drawImageEx(BG_B, currentBottomImage, TILE_ATTR_FULL(PAL2, 1, 0, 0, FG_I + 16), x, FLOOR_Y, 0, DMA); } } } // obstacle #define OBS_CEIL_Y 3 #define OBS_FLOOR_Y 20 #define OBS_X 32 #define OBS_TOP_Y FIX16(56) #define OBS_BOTTOM_Y FIX16(160) s16 fgPos, obsX; #define OBS_I FG_I + 32 SpriteDefinition* obstacleImage; s16 obstacleI; static void spawnObstacle(bool top, s16 offset, u8 type){ s16 i = -1; for(s16 j = 0; j < OBSTACLE_COUNT; j++) if(!obstacles[j].active && i == -1) i = j; if(i > -1){ // obsX = OBS_X; obsX = OBS_X + (fgPos != 0 ? (-fgPos / 8) : 0); obstacles[i].active = TRUE; obstacles[i].top = top; obstacles[i].pos.x = FIX16(256); obstacles[i].pos.y = top ? OBS_TOP_Y : OBS_BOTTOM_Y; obstacles[i].size.x = FIX16(32); obstacles[i].size.y = FIX16(32); if(offset){ obstacles[i].pos.x = fix16Sub(obstacles[i].pos.x, FIX16(offset)); obsX -= offset / 8; } obstacles[i].startX = obsX; switch(type){ case 0: obstacleImage = top ? &obstacle1LeftTop : &obstacle1LeftBottom; break; case 1: obstacleImage = top ? &obstacle1MiddleTop : &obstacle1MiddleBottom; break; case 2: obstacleImage = top ? &obstacle1RightTop : &obstacle1RightBottom; break; } obstacleI = type * 32; if(top) obstacleI += 128; VDP_drawImageEx(BG_B, obstacleImage, TILE_ATTR_FULL(PAL2, 1, 0, 0, OBS_I + obstacleI), obsX, top ? OBS_CEIL_Y : OBS_FLOOR_Y, 0, DMA); } } #define OBSTACLE_MOD FIX16(8) #define OBSTACLE_LIMIT_X FIX16(-64) SpriteDefinition* obstacleImage; static void killObstacle(s16 i){ obstacles[i].active = FALSE; VDP_clearTileMapRect(BG_B, obstacles[i].startX, obstacles[i].top ? OBS_CEIL_Y + 4 : OBS_FLOOR_Y, 4, 4); VDP_drawImageEx(BG_B, obstacles[i].top ? currentTopImage : currentBottomImage, TILE_ATTR_FULL(PAL2, 1, 0, 0, FG_I + (obstacles[i].top ? 0 : 16)), obstacles[i].startX, obstacles[i].top ? CEIL_Y : FLOOR_Y, 0, DMA_QUEUE); } static void collideObstacle(s16 i){ collideObstacleWithPlayer(i); } static void updateObstacle(s16 i){ obstacles[i].pos.x = fix16Sub(obstacles[i].pos.x, FG_SPEED); obstacles[i].pos.x <= OBSTACLE_LIMIT_X ? killObstacle(i) : collideObstacle(i); } // update #define FG_SIZE 32 #define FG_LIMIT FIX16(-512) #define FG_SIZE_F 40 s16 fgPosX[GAME_H_T]; fix16 fgPosXF[GAME_H_T]; static void scrollFg(){ for(u8 y = 0; y < GAME_H_T; y++){ if(y > 2){ fgPosXF[y] = fix16Sub(fgPosXF[y], FG_SPEED); if(fgPosXF[y] <= FG_LIMIT) fgPosXF[y] = 0; fgPosX[y] = fix16ToInt(fgPosXF[y]); } } fgPos = fgPosX[3]; } void nextFg(){ VDP_clearTileMapRect(BG_B, 0, OBS_CEIL_Y + 4, FG_W, 17); currentFg++; drawFg(); } // loop void loadFg(){ drawFg(); } void updateFg(){ VDP_setHorizontalScrollTile(BG_B, 0, fgPosX, GAME_H_T, DMA); scrollFg(); for(s16 i = 0; i < OBSTACLE_COUNT; i++) if(obstacles[i].active) updateObstacle(i); }