SDL3库实现的贪吃蛇小游戏,不到400行代码

发布时间:2026/5/26 20:23:51

SDL3库实现的贪吃蛇小游戏,不到400行代码 SDL3库实现的贪吃蛇小游戏不到400行代码SDL3库的源代码托管在https://github.com/libsdl-org/SDL官方提供了以下示例程序供开发者参考其中有一个贪吃蛇小游戏示例代码共计397行不到400行就实现了贪吃蛇的基本功能具体代码地址为https://github.com/libsdl-org/SDL/blob/main/examples/demo/01-snake/snake.cSDL官方在线程序演示https://examples.libsdl.org/SDL3/demo/01-snake/完整的SDL3实现的贪吃蛇小游戏代码/* * Logic implementation of the Snake game. It is designed to efficiently * represent the state of the game in memory. * * This code is public domain. Feel free to use it for any purpose! */#defineSDL_MAIN_USE_CALLBACKS1/* use the callbacks instead of main() */#includeSDL3/SDL.h#includeSDL3/SDL_main.h#defineSTEP_RATE_IN_MILLISECONDS125#defineSNAKE_BLOCK_SIZE_IN_PIXELS24#defineSDL_WINDOW_WIDTH(SNAKE_BLOCK_SIZE_IN_PIXELS*SNAKE_GAME_WIDTH)#defineSDL_WINDOW_HEIGHT(SNAKE_BLOCK_SIZE_IN_PIXELS*SNAKE_GAME_HEIGHT)#defineSNAKE_GAME_WIDTH24U#defineSNAKE_GAME_HEIGHT18U#defineSNAKE_MATRIX_SIZE(SNAKE_GAME_WIDTH*SNAKE_GAME_HEIGHT)#defineSNAKE_CELL_MAX_BITS3U/* floor(log2(SNAKE_CELL_FOOD)) 1 */#defineSNAKE_CELL_SET_BITS(~(~0uSNAKE_CELL_MAX_BITS))#defineSHIFT(x,y)(((x)((y)*SNAKE_GAME_WIDTH))*SNAKE_CELL_MAX_BITS)staticSDL_Joystick*joystickNULL;typedefenum{SNAKE_CELL_NOTHING0U,SNAKE_CELL_SRIGHT1U,SNAKE_CELL_SUP2U,SNAKE_CELL_SLEFT3U,SNAKE_CELL_SDOWN4U,SNAKE_CELL_FOOD5U}SnakeCell;typedefenum{SNAKE_DIR_RIGHT,SNAKE_DIR_UP,SNAKE_DIR_LEFT,SNAKE_DIR_DOWN}SnakeDirection;typedefstruct{unsignedcharcells[(SNAKE_MATRIX_SIZE*SNAKE_CELL_MAX_BITS)/8U];charhead_xpos;charhead_ypos;chartail_xpos;chartail_ypos;charnext_dir;charinhibit_tail_step;unsignedoccupied_cells;}SnakeContext;typedefstruct{SDL_Window*window;SDL_Renderer*renderer;SnakeContext snake_ctx;Uint64 last_step;}AppState;SnakeCellsnake_cell_at(constSnakeContext*ctx,charx,chary){constintshiftSHIFT(x,y);unsignedshortrange;SDL_memcpy(range,ctx-cells(shift/8),sizeof(range));return(SnakeCell)((range(shift%8))SNAKE_CELL_SET_BITS);}staticvoidset_rect_xy_(SDL_FRect*r,shortx,shorty){r-x(float)(x*SNAKE_BLOCK_SIZE_IN_PIXELS);r-y(float)(y*SNAKE_BLOCK_SIZE_IN_PIXELS);}staticvoidput_cell_at_(SnakeContext*ctx,charx,chary,SnakeCell ct){constintshiftSHIFT(x,y);constintadjustshift%8;unsignedchar*constposctx-cells(shift/8);unsignedshortrange;SDL_memcpy(range,pos,sizeof(range));range~(SNAKE_CELL_SET_BITSadjust);/* clear bits */range|(ctSNAKE_CELL_SET_BITS)adjust;SDL_memcpy(pos,range,sizeof(range));}staticintare_cells_full_(SnakeContext*ctx){returnctx-occupied_cellsSNAKE_GAME_WIDTH*SNAKE_GAME_HEIGHT;}staticvoidnew_food_pos_(SnakeContext*ctx){while(true){constcharx(char)SDL_rand(SNAKE_GAME_WIDTH);constchary(char)SDL_rand(SNAKE_GAME_HEIGHT);if(snake_cell_at(ctx,x,y)SNAKE_CELL_NOTHING){put_cell_at_(ctx,x,y,SNAKE_CELL_FOOD);break;}}}voidsnake_initialize(SnakeContext*ctx){inti;SDL_zeroa(ctx-cells);ctx-head_xposctx-tail_xposSNAKE_GAME_WIDTH/2;ctx-head_yposctx-tail_yposSNAKE_GAME_HEIGHT/2;ctx-next_dirSNAKE_DIR_RIGHT;ctx-inhibit_tail_stepctx-occupied_cells4;--ctx-occupied_cells;put_cell_at_(ctx,ctx-tail_xpos,ctx-tail_ypos,SNAKE_CELL_SRIGHT);for(i0;i4;i){new_food_pos_(ctx);ctx-occupied_cells;}}voidsnake_redir(SnakeContext*ctx,SnakeDirection dir){SnakeCell ctsnake_cell_at(ctx,ctx-head_xpos,ctx-head_ypos);if((dirSNAKE_DIR_RIGHTct!SNAKE_CELL_SLEFT)||(dirSNAKE_DIR_UPct!SNAKE_CELL_SDOWN)||(dirSNAKE_DIR_LEFTct!SNAKE_CELL_SRIGHT)||(dirSNAKE_DIR_DOWNct!SNAKE_CELL_SUP)){ctx-next_dirdir;}}staticvoidwrap_around_(char*val,charmax){if(*val0){*valmax-1;}elseif(*valmax-1){*val0;}}voidsnake_step(SnakeContext*ctx){constSnakeCell dir_as_cell(SnakeCell)(ctx-next_dir1);SnakeCell ct;charprev_xpos;charprev_ypos;/* Move tail forward */if(--ctx-inhibit_tail_step0){ctx-inhibit_tail_step;ctsnake_cell_at(ctx,ctx-tail_xpos,ctx-tail_ypos);put_cell_at_(ctx,ctx-tail_xpos,ctx-tail_ypos,SNAKE_CELL_NOTHING);switch(ct){caseSNAKE_CELL_SRIGHT:ctx-tail_xpos;break;caseSNAKE_CELL_SUP:ctx-tail_ypos--;break;caseSNAKE_CELL_SLEFT:ctx-tail_xpos--;break;caseSNAKE_CELL_SDOWN:ctx-tail_ypos;break;default:break;}wrap_around_(ctx-tail_xpos,SNAKE_GAME_WIDTH);wrap_around_(ctx-tail_ypos,SNAKE_GAME_HEIGHT);}/* Move head forward */prev_xposctx-head_xpos;prev_yposctx-head_ypos;switch(ctx-next_dir){caseSNAKE_DIR_RIGHT:ctx-head_xpos;break;caseSNAKE_DIR_UP:--ctx-head_ypos;break;caseSNAKE_DIR_LEFT:--ctx-head_xpos;break;caseSNAKE_DIR_DOWN:ctx-head_ypos;break;default:break;}wrap_around_(ctx-head_xpos,SNAKE_GAME_WIDTH);wrap_around_(ctx-head_ypos,SNAKE_GAME_HEIGHT);/* Collisions */ctsnake_cell_at(ctx,ctx-head_xpos,ctx-head_ypos);if(ct!SNAKE_CELL_NOTHINGct!SNAKE_CELL_FOOD){snake_initialize(ctx);return;}put_cell_at_(ctx,prev_xpos,prev_ypos,dir_as_cell);put_cell_at_(ctx,ctx-head_xpos,ctx-head_ypos,dir_as_cell);if(ctSNAKE_CELL_FOOD){if(are_cells_full_(ctx)){snake_initialize(ctx);return;}new_food_pos_(ctx);ctx-inhibit_tail_step;ctx-occupied_cells;}}staticSDL_AppResulthandle_key_event_(SnakeContext*ctx,SDL_Scancode key_code){switch(key_code){/* Quit. */caseSDL_SCANCODE_ESCAPE:caseSDL_SCANCODE_Q:returnSDL_APP_SUCCESS;/* Restart the game as if the program was launched. */caseSDL_SCANCODE_R:snake_initialize(ctx);break;/* Decide new direction of the snake. */caseSDL_SCANCODE_RIGHT:snake_redir(ctx,SNAKE_DIR_RIGHT);break;caseSDL_SCANCODE_UP:snake_redir(ctx,SNAKE_DIR_UP);break;caseSDL_SCANCODE_LEFT:snake_redir(ctx,SNAKE_DIR_LEFT);break;caseSDL_SCANCODE_DOWN:snake_redir(ctx,SNAKE_DIR_DOWN);break;default:break;}returnSDL_APP_CONTINUE;}staticSDL_AppResulthandle_hat_event_(SnakeContext*ctx,Uint8 hat){switch(hat){caseSDL_HAT_RIGHT:snake_redir(ctx,SNAKE_DIR_RIGHT);break;caseSDL_HAT_UP:snake_redir(ctx,SNAKE_DIR_UP);break;caseSDL_HAT_LEFT:snake_redir(ctx,SNAKE_DIR_LEFT);break;caseSDL_HAT_DOWN:snake_redir(ctx,SNAKE_DIR_DOWN);break;default:break;}returnSDL_APP_CONTINUE;}SDL_AppResultSDL_AppIterate(void*appstate){AppState*as(AppState*)appstate;SnakeContext*ctxas-snake_ctx;constUint64 nowSDL_GetTicks();SDL_FRect r;unsignedi;unsignedj;intct;// run game logic if were at or past the time to run it.// if were _really_ behind the time to run it, run it// several times.while((now-as-last_step)STEP_RATE_IN_MILLISECONDS){snake_step(ctx);as-last_stepSTEP_RATE_IN_MILLISECONDS;}r.wr.hSNAKE_BLOCK_SIZE_IN_PIXELS;SDL_SetRenderDrawColor(as-renderer,0,0,0,SDL_ALPHA_OPAQUE);SDL_RenderClear(as-renderer);for(i0;iSNAKE_GAME_WIDTH;i){for(j0;jSNAKE_GAME_HEIGHT;j){ctsnake_cell_at(ctx,i,j);if(ctSNAKE_CELL_NOTHING)continue;set_rect_xy_(r,i,j);if(ctSNAKE_CELL_FOOD)SDL_SetRenderDrawColor(as-renderer,80,80,255,SDL_ALPHA_OPAQUE);else/* body */SDL_SetRenderDrawColor(as-renderer,0,128,0,SDL_ALPHA_OPAQUE);SDL_RenderFillRect(as-renderer,r);}}SDL_SetRenderDrawColor(as-renderer,255,255,0,SDL_ALPHA_OPAQUE);/*head*/set_rect_xy_(r,ctx-head_xpos,ctx-head_ypos);SDL_RenderFillRect(as-renderer,r);SDL_RenderPresent(as-renderer);returnSDL_APP_CONTINUE;}staticconststruct{constchar*key;constchar*value;}extended_metadata[]{{SDL_PROP_APP_METADATA_URL_STRING,https://examples.libsdl.org/SDL3/demo/01-snake/},{SDL_PROP_APP_METADATA_CREATOR_STRING,SDL team},{SDL_PROP_APP_METADATA_COPYRIGHT_STRING,Placed in the public domain},{SDL_PROP_APP_METADATA_TYPE_STRING,game}};SDL_AppResultSDL_AppInit(void**appstate,intargc,char*argv[]){size_ti;if(!SDL_SetAppMetadata(Example Snake game,1.0,com.example.Snake)){returnSDL_APP_FAILURE;}for(i0;iSDL_arraysize(extended_metadata);i){if(!SDL_SetAppMetadataProperty(extended_metadata[i].key,extended_metadata[i].value)){returnSDL_APP_FAILURE;}}if(!SDL_Init(SDL_INIT_VIDEO|SDL_INIT_JOYSTICK)){SDL_Log(Couldnt initialize SDL: %s,SDL_GetError());returnSDL_APP_FAILURE;}AppState*as(AppState*)SDL_calloc(1,sizeof(AppState));if(!as){returnSDL_APP_FAILURE;}*appstateas;if(!SDL_CreateWindowAndRenderer(examples/demo/snake,SDL_WINDOW_WIDTH,SDL_WINDOW_HEIGHT,SDL_WINDOW_RESIZABLE,as-window,as-renderer)){returnSDL_APP_FAILURE;}SDL_SetRenderLogicalPresentation(as-renderer,SDL_WINDOW_WIDTH,SDL_WINDOW_HEIGHT,SDL_LOGICAL_PRESENTATION_LETTERBOX);snake_initialize(as-snake_ctx);as-last_stepSDL_GetTicks();returnSDL_APP_CONTINUE;}SDL_AppResultSDL_AppEvent(void*appstate,SDL_Event*event){SnakeContext*ctx((AppState*)appstate)-snake_ctx;switch(event-type){caseSDL_EVENT_QUIT:returnSDL_APP_SUCCESS;caseSDL_EVENT_JOYSTICK_ADDED:if(joystickNULL){joystickSDL_OpenJoystick(event-jdevice.which);if(!joystick){SDL_Log(Failed to open joystick ID %u: %s,(unsignedint)event-jdevice.which,SDL_GetError());}}break;caseSDL_EVENT_JOYSTICK_REMOVED:if(joystick(SDL_GetJoystickID(joystick)event-jdevice.which)){SDL_CloseJoystick(joystick);joystickNULL;}break;caseSDL_EVENT_JOYSTICK_HAT_MOTION:returnhandle_hat_event_(ctx,event-jhat.value);caseSDL_EVENT_KEY_DOWN:returnhandle_key_event_(ctx,event-key.scancode);default:break;}returnSDL_APP_CONTINUE;}voidSDL_AppQuit(void*appstate,SDL_AppResult result){if(joystick){SDL_CloseJoystick(joystick);}if(appstate!NULL){AppState*as(AppState*)appstate;SDL_DestroyRenderer(as-renderer);SDL_DestroyWindow(as-window);SDL_free(as);}}

相关新闻