#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #define DEFAULT_PORT "27015" #define DEFAULT_BUFLEN 512 #include <windows.h> #include <winsock2.h> #include <ws2tcpip.h> #include <iphlpapi.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #include <process.h> FILE *users;//user database file for account making and logging in FILE *usernames;//list of taken usernames struct user { SOCKET connection;//socket user is connected to char username[20];//their username }; struct user *connecters;//dynamic list of connected users int length=0;//length of connected users struct user* remove_element(struct user* array, int sizeOfArray, int indexToRemove){ struct user* temp = malloc((sizeOfArray - 1) * sizeof(struct user)); // allocate an array with a size 1 less than the current one if (indexToRemove != 0) memcpy(temp, array, indexToRemove * sizeof(struct user)); // copy everything BEFORE the index if (indexToRemove != (sizeOfArray - 1)) memcpy(temp+indexToRemove, array+indexToRemove+1, (sizeOfArray - indexToRemove - 1) * sizeof(struct user)); // copy everything AFTER the index free (array); return temp; } unsigned __stdcall ClientSession(void *data){//multithreading, gonna be real with you I have no idea how this code works SOCKET ClientSocket = (SOCKET)data;// Process the client. //message receiving setup stuff char message[DEFAULT_BUFLEN]; int buffer;//function recorder int buffer2;//another function recorder int iSendResult; int messageSize = DEFAULT_BUFLEN; char sender[100];//user that is sending stuff //login shit bool logger=false; char accounter[1];//records if they have an account do {//it has to be a do while so the thread ends properly buffer2=recv(ClientSocket, accounter, 1, 0);//checking if they need to make a new account or can log in printf("%d\n",buffer2); if (!(buffer2>=0)){ printf("recv failed: %d\n", WSAGetLastError()); closesocket(ClientSocket); return 1; } if (accounter[0]=='N'){ users=fopen("users.txt","a");//opens the user recording file char holder[2][20];//holds the login info while (true){ usernames=fopen("usernames.txt","r");//opens the username list file bool taken=false; buffer2=recv(ClientSocket, holder[0], 20, 0);//getting the username if (!(buffer2>=0)){ printf("recv failed: %d\n", WSAGetLastError()); closesocket(ClientSocket); return 1; } if (strcmp(holder[0]," ")==0){//checks if it's just a timeout space memset(holder[0], 0, sizeof(holder[0]));//resetting login info if it's just a space continue; } //checks if the username is taken char checker[100]; while(fgets(checker, 100, usernames)) { if (checker[strlen(checker)-1]== '\n') checker[strlen(checker)-1]='\0'; if (strcmp(checker,holder[0])==0){ taken=true; char denier[]="taken"; send(ClientSocket, denier, (int)strlen(denier), 0); break; } } fclose(usernames); if (taken) continue; char accepter[]="okie-dokie"; send(ClientSocket, accepter, (int)strlen(accepter), 0); break; } while (true){ buffer2=recv(ClientSocket, holder[1], 20, 0);//getting the login info if (!(buffer2>=0)){ printf("recv failed: %d\n", WSAGetLastError()); closesocket(ClientSocket); return 1; } if (strcmp(holder[1]," ")==0){ memset(holder[1], 0, sizeof(holder[1]));//resetting login info if it's just a space continue; } break; } //recording the new account char account[] = " username: "; strcat(account,holder[0]); strcat(account," password: "); strcat(account,holder[1]); strcat(account,"\n"); fprintf(users,account);//recording login info strcat(holder[0],"\n"); usernames=fopen("usernames.txt","a"); fprintf(usernames,holder[0]);//recording the username fclose(users); fclose(usernames); } if (accounter[0]=='Y'){ char holder[2][20];//stores login info while (true){ buffer2=recv(ClientSocket, holder[0], 20, 0);//getting the login info if (!(buffer2>=0)){ printf("recv failed: %d\n", WSAGetLastError()); closesocket(ClientSocket); return 1; } if (strcmp(holder[0]," ")==0){ memset(holder[0], 0, sizeof(holder[0]));//resetting login info if it's just a space continue; } break; } while (true){ buffer2=recv(ClientSocket, holder[1], 20, 0);//getting the login info if (!(buffer2>=0)){ printf("recv failed: %d\n", WSAGetLastError()); closesocket(ClientSocket); return 1; } if (strcmp(holder[1]," ")==0){ memset(holder[1], 0, sizeof(holder[1]));//resetting login info if it's just a space continue; } break; } char account[] = " username: "; strcat(account,holder[0]); strcat(account," password: "); strcat(account,holder[1]); printf("%s\n",account); char accountBuffer[100]; bool noper=false; users=fopen("users.txt","r"); while (fgets(accountBuffer, 100, users)){ if (accountBuffer[strlen(accountBuffer)-1]== '\n') accountBuffer[strlen(accountBuffer)-1]='\0';//checks if last character is newline if (strcmp(account,accountBuffer)==0){ //login confirmation stuff logger=true; send(ClientSocket, "Y", 1, 0);//yes they logged in right printf("Logged in\n"); length++; connecters=realloc(connecters,length*sizeof(struct user)); struct user newGuy = { .connection=ClientSocket }; memcpy(newGuy.username, holder[0], 20); connecters[length-1]=newGuy; fclose(users); strcpy(sender,holder[0]); noper=true; break; } } if (!noper) send(ClientSocket, "N", 1, 0);//no they logged in wrong memset(holder[0], 0, sizeof(holder[0]));//resetting the login info memset(holder[1], 0, sizeof(holder[1]));//resetting the login info } } while (!logger&&buffer2>0);//making it so the thread ends properly if connection is insantly abandoned // Receive until the peer shuts down the connection do { memset(message, 0, sizeof(message));//resetting the message buffer = recv(ClientSocket, message, messageSize, 0);//receiving the message if (buffer > 0) { if (strcmp(message," ")==0) continue; printf("%s\n",message);//prints message they sent char receiver[50]; memset(receiver, 0, sizeof(receiver));//resetting this because for some reason it doesn't work when I don't while (true){ buffer2=recv(ClientSocket, receiver, 20, 0);//receiving the receiver if (!(buffer2>=0)){ printf("recv failed: %d\n", WSAGetLastError()); closesocket(ClientSocket); return 1; } if (strcmp(receiver," ")==0){ memset(receiver, 0, sizeof(receiver));//resetting the receiver if it's just a space continue; } break; } //searches for user to send the message to for (int i=0;i<length;i++){ if (strcmp(connecters[i].username,receiver)==0){ iSendResult = send(connecters[i].connection, sender, sizeof(sender), 0); if (iSendResult == SOCKET_ERROR) { printf("send failed: %d\n", WSAGetLastError()); closesocket(ClientSocket); return 1; } //send message to correct person iSendResult = send(connecters[i].connection, message, sizeof(message), 0); if (iSendResult == SOCKET_ERROR) { printf("send failed: %d\n", WSAGetLastError()); closesocket(ClientSocket); return 1; } } } } else if (buffer == 0) printf("Connection closing...\n"); else { printf("recv failed: %d\n", WSAGetLastError()); for (int i=0;i<length;i++){ if (connecters[i].connection==ClientSocket&&strcmp(connecters[i].username,sender)==0){ connecters = remove_element(connecters, length, i); length--; } } closesocket(ClientSocket); return 1; } } while (buffer > 0); //removing them from the list for (int i=0;i<length;i++){ if (connecters[i].connection==ClientSocket&&strcmp(connecters[i].username,sender)==0){ connecters = remove_element(connecters, length, i); length--; } } closesocket(ClientSocket); printf("thread ended\n"); return 0; } int main(){ connecters=(struct user*)malloc(length * sizeof(struct user));//list of connected users //winsock setup variables WSADATA wsaData; int buffer; struct sockaddr_in service;//struct that stores ip address // Initialize Winsock buffer = WSAStartup(MAKEWORD(2,2), &wsaData); if (buffer != 0) { printf("WSAStartup failed: %d\n", buffer); return 1; } // Create a SOCKET for listening for // incoming connection requests SOCKET ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ListenSocket == INVALID_SOCKET) { wprintf(L"socket function failed with error: %u\n", WSAGetLastError()); WSACleanup(); return 1; } // The sockaddr_in structure specifies the address family, // IP address, and port for the socket that is being bound. service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr("172.16.226.210");//ip to bind to service.sin_port = htons(27015);//port // Bind the socket. buffer = bind(ListenSocket, (SOCKADDR *) &service, sizeof (service)); if (buffer == SOCKET_ERROR) { wprintf(L"bind failed with error %u\n", WSAGetLastError()); closesocket(ListenSocket); WSACleanup(); return 1; } //listening for incoming socket while (true){ if ( listen( ListenSocket, SOMAXCONN ) == SOCKET_ERROR ) { printf( "Listen failed with error: %d\n", WSAGetLastError() ); closesocket(ListenSocket); WSACleanup(); return 1; } SOCKET ClientSocket; ClientSocket = INVALID_SOCKET; // Accept a client socket ClientSocket = accept(ListenSocket, NULL, NULL); printf("%llu\n",ClientSocket);//printing the client socket if (ClientSocket == INVALID_SOCKET) { printf("accept failed: %d\n", WSAGetLastError()); closesocket(ListenSocket); WSACleanup(); return 1; } // Create a new thread for the accepted client (also pass the accepted client socket). unsigned threadID; (HANDLE)_beginthreadex(NULL, 0, &ClientSession, (void*)ClientSocket, 0, &threadID); } // cleanup WSACleanup(); printf("socket adventures"); return 0; }
This is server for a messaging app written in pure C using the winsock library. It has a login system that allows users to sign in with a username of their choice (provided that username isn't taken) and password. It also has an address system that determines which users are signed in. The app works by a user sending a message, indicating who they want to send the message to, and the server sends that message to the person addressed, provided they are online and signed in. A very simple but effective chat app, similar to the chat apps of the early 90s. The server runs based off a custom database design and remembers login infos long after the client signs off, or the server goes down. A lot of this was difficult to design as I had to work with both the client and server side of things simultaneously. I always find myself coming back to this project to add more features and whatnot.
#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #define DEFAULT_BUFLEN 512 #define DEFAULT_PORT "27015" #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> #include <time.h> #include <process.h> #include <math.h> #include <SDL2/SDL.h> #include <SDL2/SDL_image.h> #include <SDL2/SDL_ttf.h> #include <windows.h> #include <winsock2.h> #include <ws2tcpip.h> #include <iphlpapi.h> #define PI atan(1)*4 char lastMessage[100]; //circle maker void drawCircle(SDL_Renderer *renderer, int x, int y, int radius){ for (int w = 0; w < radius * 2; w++) { for (int h = 0; h < radius * 2; h++) { int dx = radius - w; // horizontal offset int dy = radius - h; // vertical offset if ((dx*dx + dy*dy) <= (radius * radius)) SDL_RenderDrawPoint(renderer, x + dx, y + dy); } } } void delay(int number_of_seconds){ int milli_seconds = 1000 * number_of_seconds;// Converting time into milli_seconds clock_t start_time = clock();// Storing start time while (clock() < start_time + milli_seconds);// looping till required time is not achieved } unsigned __stdcall ClientSession(void *data){//multithreading to stop timeout bug SOCKET ConnectSocket = (SOCKET)data;// Process the client. char message[]=" ";//blank message to send server int buffer; while (true){ delay(240);//delay of 4 minutes buffer = send( ConnectSocket, message, (int)strlen(message), 0 );//sending server a blank message to keep connection going if (buffer == SOCKET_ERROR) { printf("send failed with error: %d\n", WSAGetLastError()); closesocket(ConnectSocket); WSACleanup(); return 1; } } return 0; } unsigned __stdcall messageListener(void *data){//multithreading to receive messages SOCKET ConnectSocket = (SOCKET)data;// Process the client. char message[DEFAULT_BUFLEN];//message holder char sender[50]; int buffer; while (true){ recv(ConnectSocket, sender, DEFAULT_BUFLEN, 0);//getting the user recv(ConnectSocket, message, DEFAULT_BUFLEN, 0);//getting the message strcat(sender," : "); strcat(sender,message); memset(lastMessage,0,sizeof(lastMessage)); strcpy(lastMessage,sender); memset(message, 0, sizeof(message));//resetting the message memset(sender, 0, sizeof(sender));//resetting the message } return 0; } const int width=1024,height=576;//screen proportions int main(int argc,char **argv){ strcpy(lastMessage,""); //SDL setup stuff bool quit = false; SDL_Event event; SDL_Init( SDL_INIT_EVERYTHING ); IMG_Init(IMG_INIT_PNG); IMG_Init(IMG_INIT_JPG); TTF_Init(); //winsock stuff WSADATA wsaData; SOCKET ConnectSocket = INVALID_SOCKET;// connecting socket char message[DEFAULT_BUFLEN];//message holder char receive[DEFAULT_BUFLEN];//received message storage int buffer; // Initialize Winsock buffer = WSAStartup(MAKEWORD(2, 2), &wsaData); if (buffer != NO_ERROR) { wprintf(L"WSAStartup function failed with error: %d\n", buffer); return 1; } // Create a SOCKET for connecting to server ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ConnectSocket == INVALID_SOCKET) { wprintf(L"socket function failed with error: %d\n", WSAGetLastError()); WSACleanup(); return 1; } // The sockaddr_in structure specifies the address family, // IP address, and port of the server to be connected to. struct sockaddr_in clientService; clientService.sin_family = AF_INET; clientService.sin_addr.s_addr = inet_addr("172.16.226.210");//where it's connecting clientService.sin_port = htons(27015);//port // Connect to server. buffer = connect(ConnectSocket, (SOCKADDR *) & clientService, sizeof (clientService)); if (buffer == SOCKET_ERROR) { wprintf(L"connect function failed with error: %ld\n", WSAGetLastError()); buffer = closesocket(ConnectSocket); if (buffer == SOCKET_ERROR) wprintf(L"closesocket function failed with error: %ld\n", WSAGetLastError()); WSACleanup(); return 1; } //setting up timeout prevention unsigned threadID; (HANDLE)_beginthreadex(NULL, 0, &ClientSession, (void*)ConnectSocket, 0, &threadID); //end of client setup stuff SDL_Window * window = SDL_CreateWindow("messaging app",SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, 0);//creating a window SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);//creating the renderer SDL_Surface * screen=SDL_CreateRGBSurface(0,width,height,32,0,0,0,0); TTF_Font* Sans = TTF_OpenFont("The Wild Breath of Zelda.otf", 24);//setting up the font SDL_Surface * icon=IMG_Load("penisforeskinicon.JPG");//icon SDL_Color black = {0, 0, 0}; SDL_SetRenderDrawColor(renderer,20,0,123,0); char input[DEFAULT_BUFLEN]; strcpy(input,""); char prompt[100]; strcpy(prompt,"do you have an account? Enter Y for yes, or N for no" ); char screenType[20]; strcpy(screenType,"login"); //login variables bool logger=false; char login[2][20]; char accounter[1]; char text[100];//message //universal screen rects SDL_Rect topbar; topbar.y=0; topbar.x=0; topbar.h=80; topbar.w=width; SDL_Rect titleRect; //create a rect titleRect.w = 100; // controls the width of the rect titleRect.h = 60; // controls the height of the rect titleRect.x = width/2 -titleRect.w/2; //controls the rect's x coordinate titleRect.y = topbar.y+15; // controls the rect's y coordinte SDL_Rect bottombar; bottombar.y=height-20; bottombar.x=0; bottombar.h=20; bottombar.w=width; SDL_Rect sq1; sq1.w=100; sq1.h=60; sq1.x=topbar.x+20; sq1.y=topbar.y+10; SDL_Rect sq2; sq2.w=100; sq2.h=60; sq2.x=sq1.x+sq1.w+20; sq2.y=topbar.y+10; SDL_Rect sq3; sq3.w=100; sq3.h=60; sq3.x=sq2.x+sq2.w+20; sq3.y=topbar.y+10; SDL_Rect sq4; sq4.w=100; sq4.h=60; sq4.x=topbar.w-sq4.w-20; sq4.y=topbar.y+10; SDL_Rect sq5; sq5.w=100; sq5.h=60; sq5.x=sq4.x-sq5.w-20; sq5.y=topbar.y+10; SDL_Rect sq6; sq6.w=100; sq6.h=60; sq6.x=sq5.x-sq6.w-20; sq6.y=topbar.y+10; SDL_Rect squares[]={sq1,sq2,sq3,sq4,sq5,sq6}; //login screen rects SDL_Rect loginSquare; loginSquare.w=400; loginSquare.h=250; loginSquare.x=width/2-loginSquare.w/2; loginSquare.y=height/2-loginSquare.h/2; SDL_Rect loginInput; loginInput.w=70; loginInput.h=70; loginInput.x=loginSquare.x+loginSquare.w/2 -loginInput.w/2; loginInput.y=loginSquare.h-loginInput.h/2; SDL_Rect promptBox; promptBox.w=10*strlen(prompt); promptBox.h=40; promptBox.x=loginSquare.x; promptBox.y=loginSquare.y-50; //messaging rects SDL_Rect personBox; personBox.w=width; personBox.h=40; personBox.x=0; personBox.y=topbar.h; SDL_Rect sendBox; sendBox.w=400; sendBox.h=550; sendBox.x=40; sendBox.y=height-10; SDL_Rect label; label.w=300; label.h=60; label.x=width/2-label.w/2; label.y=personBox.y+personBox.h+20; SDL_Rect m1; m1.w=300; m1.h=60; m1.x=width/2-m1.w/2; m1.y=height/2-m1.h/2+label.h; //Enable text input SDL_StartTextInput(); SDL_Event windowEvent; SDL_SetWindowIcon(window, icon); while (true){ if (SDL_PollEvent(&windowEvent)){ if (SDL_QUIT==windowEvent.type){ break; } } if( windowEvent.type == SDL_KEYDOWN ){ //Handle backspace if( windowEvent.key.keysym.sym == SDLK_BACKSPACE && strlen(input) > 0 ){ //lop off character input[strlen(input)-1]='\0'; } //handling enter button if( windowEvent.key.keysym.sym == SDLK_RETURN && strlen(input) > 0 ){ //account input if (strcmp(screenType,"login")==0&&strlen(accounter)==0&&strlen(input)!=0&&strcmp(prompt,"do you have an account? Enter Y for yes, or N for no")==0){ if (strlen(input)!=1){ memset(input,0,sizeof(input)); strcpy(input,""); strcpy(accounter,input); } else { memset(accounter,0,sizeof(accounter)); strcpy(accounter,input); accounter[0]=toupper(accounter[0]); } if (accounter[0]=='N'||accounter[0]=='Y'){ bool newUsername=false; memset(input,sizeof(input),0); strcpy(input,""); memset(prompt,sizeof(prompt),0); if (accounter[0]=='Y') strcpy(prompt,"enter your username"); else strcpy(prompt,"create an account, enter your username"); promptBox.w=10*strlen(prompt); send( ConnectSocket, accounter, 1, 0 );//sending if user wants to make new account } else { memset(input,0,sizeof(input)); strcpy(input,""); strcpy(accounter,input); } //login info if you do have an account } else if (strcmp(screenType,"login")==0&&strlen(input)!=0&&strcmp(prompt,"enter your username")==0){ strcpy(login[0],input); send( ConnectSocket, login[0], sizeof(login[0]), 0 );//sending login info memset(input,sizeof(input),0); strcpy(input,""); memset(prompt,sizeof(prompt),0); strcpy(prompt,"enter your password"); promptBox.w=10*strlen(prompt); //login info if you do have an account password } else if (strcmp(screenType,"login")==0&&strlen(input)!=0&&strcmp(prompt,"enter your password")==0&&accounter[0]=='Y'){ strcpy(login[1],input); send( ConnectSocket, login[1], sizeof(login[1]), 0 );//sending login info memset(input,sizeof(input),0); strcpy(input,""); recv(ConnectSocket, accounter, 1, 0); if (accounter[0]=='Y'){ memset(prompt,sizeof(prompt),0); strcpy(prompt,"You're logged in!"); //message listening unsigned listener; (HANDLE)_beginthreadex(NULL, 0, &messageListener, (void*)ConnectSocket, 0, <istener); promptBox.w=10*strlen(prompt); } else { memset(prompt,sizeof(prompt),0); strcpy(prompt,"Wrong login"); promptBox.w=10*strlen(prompt); } memset(login[0], 0, sizeof(login[0]));//resetting the login info memset(login[1], 0, sizeof(login[1]));//resetting the login info memset(accounter, 0, sizeof(accounter));//resetting the login info //login if you're making an account username } else if (strcmp(screenType,"login")==0&&strlen(input)!=0&&(strcmp(prompt,"create an account, enter your username")==0||strcmp(prompt,"username taken, please pick a new one")==0)){ memset(login[0], 0, sizeof(login[0]));//resetting the login info strcpy(login[0],input); send( ConnectSocket, login[0], sizeof(login[0]), 0 );//sending login info char checker[strlen("okie-dokie")+1]; recv(ConnectSocket, checker, strlen("okie-dokie"), 0); printf(checker); if (strcmp(checker,"okie-dokie")==0){ memset(input,sizeof(input),0); strcpy(input,""); memset(prompt,sizeof(prompt),0); strcpy(prompt,"enter your password"); promptBox.w=10*strlen(prompt); } else { memset(input,sizeof(input),0); strcpy(input,""); memset(prompt,sizeof(prompt),0); strcpy(prompt,"username taken, please pick a new one"); promptBox.w=10*strlen(prompt); } //account creation for no account } else if (strcmp(screenType,"login")==0&&strlen(input)!=0&&strcmp(prompt,"enter your password")==0&&accounter[0]=='N'){ strcpy(login[1],input); send( ConnectSocket, login[1], sizeof(login[1]), 0 );//sending login info memset(input,sizeof(input),0); strcpy(input,""); memset(login[0], 0, sizeof(login[0]));//resetting the login info memset(login[1], 0, sizeof(login[1]));//resetting the login info memset(accounter, 0, sizeof(accounter));//resetting the login info memset(prompt,sizeof(prompt),0); strcpy(prompt,"account created"); promptBox.w=10*strlen(prompt); } else if (strcmp(screenType,"messaging")==0&&strlen(input)!=0&&strcmp(prompt,"enter the message you want to send")==0){ memset(text,0,sizeof(text)); strcpy(text,input); memset(input,0,sizeof(input)); strcpy(input,""); // Sending a message send( ConnectSocket, text, (int)strlen(text), 0 ); memset(prompt,0,sizeof(prompt)); strcpy(prompt,"who do you want to message?"); } else if (strcmp(screenType,"messaging")==0&&strlen(input)!=0&&strcmp(prompt,"who do you want to message?")==0){ char receiver[40]; strcpy(receiver,input); send( ConnectSocket, receiver, (int)strlen(receiver), 0 );//message memset(input,sizeof(input),0); strcpy(input,""); memset(prompt,sizeof(prompt),0); strcpy(prompt,"enter the message you want to send"); } } } //Special text input event else if( windowEvent.type == SDL_TEXTINPUT ){ //Not copy or pasting if( !( SDL_GetModState() & KMOD_CTRL && ( windowEvent.text.text[ 0 ] == 'c' || windowEvent.text.text[ 0 ] == 'C' || windowEvent.text.text[ 0 ] == 'v' || windowEvent.text.text[ 0 ] == 'V' ) ) ) { //Append character if (strcmp(prompt,"do you have an account? Enter Y for yes, or N for no")==0&&strlen(input)==0) strcat( input,windowEvent.text.text); else if (strcmp(prompt,"do you have an account? Enter Y for yes, or N for no")!=0) strcat( input,windowEvent.text.text); } } SDL_FillRect(screen,NULL,230219217); SDL_FillRect(screen,&topbar,122241255); SDL_FillRect(screen,&bottombar,122241255); //coloring in the boxes for the login screen if (strcmp(screenType,"login")==0){ SDL_FillRect(screen,<oginSquare,122241255); SDL_FillRect(screen,<oginInput,255255255); SDL_FillRect(screen,&promptBox,122241255); } if (strcmp(screenType,"messaging")==0){ SDL_FillRect(screen,&sendBox,255255255); SDL_FillRect(screen,&personBox,255255255); } SDL_Texture * texture=SDL_CreateTextureFromSurface(renderer, screen); SDL_RenderCopy(renderer, texture, NULL, NULL);//placing the background SDL_Surface* title = TTF_RenderText_Solid(Sans, "HERMES", black);//title SDL_Texture* titleText = SDL_CreateTextureFromSurface(renderer, title); SDL_RenderCopy(renderer, titleText, NULL, &titleRect); //text for login screen if (strcmp(screenType,"login")==0){ char* promptBuf=prompt; SDL_Surface* psurface = TTF_RenderText_Solid(Sans, promptBuf, black);//prompt SDL_Texture* ptext = SDL_CreateTextureFromSurface(renderer, psurface); SDL_RenderCopy(renderer, ptext, NULL, &promptBox); char* inputBuf=input; SDL_Surface* isurface = TTF_RenderText_Solid(Sans, inputBuf, black);//prompt SDL_Texture* itext = SDL_CreateTextureFromSurface(renderer, isurface); //fixing the text resize bug SDL_Rect loginInputT; loginInputT.x=loginInput.x; loginInputT.y=loginInput.y; loginInputT.w=loginInput.w; loginInputT.h=loginInput.h; TTF_SetFontSize(Sans, 70); if (strlen(inputBuf)!=0) { loginInputT.w=isurface->w; loginInputT.h=isurface->h; if (strcmp(prompt,"do you have an account? Enter Y for yes, or N for no")!=0) { loginInput.w=isurface->w; loginInput.h=isurface->h; } else { loginInput.w=70; loginInput.h=70; } loginInput.x=loginSquare.x+loginSquare.w/2 -loginInput.w/2; loginInput.y=loginSquare.h-loginInput.h/2; } SDL_RenderCopy(renderer, itext, NULL, <oginInputT); SDL_FreeSurface(psurface); SDL_DestroyTexture(ptext); SDL_FreeSurface(isurface); SDL_DestroyTexture(itext); } //text for messaging screen if (strcmp(screenType,"messaging")==0){ char* inputBuf=input; TTF_SetFontSize(Sans, 40); SDL_Surface* isurface = TTF_RenderText_Solid(Sans, inputBuf, black);//prompt SDL_Texture* itext = SDL_CreateTextureFromSurface(renderer, isurface); if (strlen(inputBuf)!=0){ sendBox.w=isurface->w; sendBox.h=isurface->h; } else { sendBox.w=400; sendBox.h=50; } SDL_RenderCopy(renderer, itext, NULL, &sendBox); char* promptBuf=prompt; SDL_Surface* psurface = TTF_RenderText_Solid(Sans, promptBuf, black);//prompt SDL_Texture* ptext = SDL_CreateTextureFromSurface(renderer, psurface); SDL_RenderCopy(renderer, ptext, NULL, &personBox); char* labelText="last message received"; SDL_Surface* lsurface = TTF_RenderText_Solid(Sans, labelText, black);//prompt SDL_Texture* ltext = SDL_CreateTextureFromSurface(renderer, lsurface); SDL_RenderCopy(renderer, ltext, NULL, <abel); char* lastText=lastMessage; TTF_SetFontSize(Sans, 40-strlen(lastMessage)/30); SDL_Surface* ltsurface = TTF_RenderText_Solid(Sans, lastText, black);//prompt SDL_Texture* lttext = SDL_CreateTextureFromSurface(renderer, ltsurface); if (strlen(lastMessage)!=0){ m1.w=ltsurface->w; m1.h=ltsurface->h; m1.x=width/2-m1.w/2; m1.y=height/2-m1.h/2+label.h; } TTF_SetFontSize(Sans, 70); SDL_RenderCopy(renderer, lttext, NULL, &m1); SDL_FreeSurface(isurface); SDL_DestroyTexture(itext); SDL_FreeSurface(psurface); SDL_DestroyTexture(ptext); SDL_FreeSurface(lsurface); SDL_DestroyTexture(ltext); SDL_FreeSurface(ltsurface); SDL_DestroyTexture(lttext); } for (int i=0;i<6;i++) drawCircle(renderer,squares[i].x+squares[i].w/2,squares[0].y+squares[0].h/2,30); SDL_RenderPresent(renderer); // Don't forget to free your surface and texture SDL_FreeSurface(title); SDL_DestroyTexture(titleText); SDL_DestroyTexture(texture); if (strcmp(prompt,"Wrong login")==0||strcmp(prompt,"account created")==0){ SDL_Delay(500); memset(prompt,sizeof(prompt),0); strcpy(prompt,"do you have an account? Enter Y for yes, or N for no"); promptBox.w=10*strlen(prompt); memset(input,sizeof(input),0); strcpy(input,""); } if (strcmp(prompt,"You're logged in!")==0) { SDL_Delay(500); memset(screenType,0,sizeof(screenType)); strcpy(screenType,"messaging"); memset(prompt,sizeof(prompt),0); strcpy(prompt,"enter the message you want to send"); bottombar.y-=50; bottombar.h+=50; sendBox.y-=50; sendBox.h-=200; } } //cleanup SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); TTF_Quit(); IMG_Quit(); SDL_Quit(); shutdown(ConnectSocket, SD_SEND); closesocket(ConnectSocket); WSACleanup(); return 0; }
This is the client side of the messaging app, again, written entirely in C. The client functions by connecting to the server (obviously the server and client are binded to the right IP, although this would vary if you tried running this at home) and then allowing you to login. The GUI was made using SDL2. Getting the client and server side to sync up along with the GUI was a massively fun (even if nightmarish) process, but I enjoyed it and I always try to think of ways to modify and improve this code, below is an example of 2 of the clients communicating with each other
#include <iostream> #include <memory> #include <Windows.h> #include <process.h> #include <string> #include <SDL2/SDL.h> #include <SDL2/SDL_image.h> #include <SDL2/SDL_ttf.h> const int width=1024,height=576;//screen proportions const double gravity=0.7;//gravity bool end=false;//value to see if the game ended struct spriteTemplate {//sprite struct std::string imageSrc; std::string backwardsImg; int framesMax; int framesHold; struct { int height; int width; } scales; int offset; }; struct character {//character struct double position[2]; double velocity[2]; struct { int x; int y; int width; int height; int knockback; int frame; } attackStats; std::string imageSrc; int framesMax; int framesHold; int framesElapsed; int currentFrame=1; struct { spriteTemplate idle; spriteTemplate run; spriteTemplate jump; spriteTemplate fall; spriteTemplate attack1; spriteTemplate takeHit; spriteTemplate death; } sprites; int height; int width; int speed; int jumpH; int offset; }; character Richard { {400,100},//position {0,0},//velocity { 50,//x 67,//y 200,//width 100,//height 30,//knockback 3//frame },//attackStats "richardIdle.png",//imgSrc 8,//framesMax 6,//framesHold 0,//framesElapsed 1,//currentFrame {//sprites struct { "richardIdle.png", "richardIdlebackwards.png", 8, 6, { 200, 250 }, 16 }, { "richardRun.png", "richardRunbackwards.png", 7, 9, { 200, 250 }, 0 }, { "richardJump.png", "richardJumpbackwards.png", 2, 12, { 230, 260 }, 20 }, { "richardFall.png", "richardFallbackwards.png", 2, 5, { 200, 250 }, 30 }, { "richardAttack1.png", "richardAttack1backwards.png", 5, 8, { 200, 250 }, 0 }, { "richardTake hit.png", "richardTake hitbackwards.png", 5, 4, { 200, 250 }, 23 }, { "richardDeath.png", "richardDeathbackwards.png", 9, 6, { 200, 250 }, 0 } }, 200,//height 250,//width 3,//speed 13,//jump height 16//offset }; character Dracaena { {0,100},//position {0,0},//velocity { 90,//x 38,//y 93,//width 58,//height 20,//knockback 3//frame },//attackStats "dracIdle.png",//imgSrc 4,//framesMax 15,//framesHold 0,//framesElapsed 1,//currentFrame {//sprites struct { "dracIdle.png", "dracIdlebackwards.png", 4, 15, { 170, 180 }, 70 }, { "dracRun.png", "dracRunbackwards.png", 11, 7, { 170, 210 }, 15 }, { "dracJump.png", "dracJumpbackwards.png", 3, 7, { 160, 190 }, 100 }, { "dracFall.png", "dracFallbackwards.png", 2, 2, { 150, 180 }, 100 }, { "dracAttack1.png", "dracAttack1backwards.png", 4, 10, { 170, 210 }, 40 }, { "dracTake hit.png", "dracTake hitbackwards.png", 3, 11, { 170, 190 }, 132 }, { "dracDeath.png", "dracDeathbackwards.png", 10, 9, { 170, 210 }, 20 } }, 170,//height 210,//width 6,//speed 15,//jump height 106//offset }; struct { struct { bool pressed=false; } a; struct { bool pressed=false; } d; struct { bool pressed=false; } w; struct { bool pressed=false; } ArrowLeft; struct { bool pressed=false; } ArrowRight; struct { bool pressed=false; } ArrowUp; } keys; class LTimer { public: //Initializes variables LTimer(); //The various clock actions void start(); void stop(); void pause(); void unpause(); //Gets the timer's time Uint32 getTicks(); //Checks the status of the timer bool isStarted(); bool isPaused(); private: //The clock time when the timer started Uint32 mStartTicks; //The ticks stored when the timer was paused Uint32 mPausedTicks; //The timer status bool mPaused; bool mStarted; }; LTimer::LTimer(){ //Initialize the variables mStartTicks = 0; mPausedTicks = 0; mPaused = false; mStarted = false; } void LTimer::start(){ //Start the timer mStarted = true; //Unpause the timer mPaused = false; //Get the current clock time mStartTicks = SDL_GetTicks(); mPausedTicks = 0; } void LTimer::stop(){ //Stop the timer mStarted = false; //Unpause the timer mPaused = false; //Clear tick variables mStartTicks = 0; mPausedTicks = 0; } void LTimer::pause(){ //If the timer is running and isn't already paused if( mStarted && !mPaused ) { //Pause the timer mPaused = true; //Calculate the paused ticks mPausedTicks = SDL_GetTicks() - mStartTicks; mStartTicks = 0; } } void LTimer::unpause(){ //If the timer is running and paused if( mStarted && mPaused ) { //Unpause the timer mPaused = false; //Reset the starting ticks mStartTicks = SDL_GetTicks() - mPausedTicks; //Reset the paused ticks mPausedTicks = 0; } } Uint32 LTimer::getTicks(){ //The actual timer time Uint32 time = 0; //If the timer is running if( mStarted ) { //If the timer is paused if( mPaused ) { //Return the number of ticks when the timer was paused time = mPausedTicks; } else { //Return the current time minus the start time time = SDL_GetTicks() - mStartTicks; } } return time; } bool LTimer::isStarted(){ //Timer is running and paused or unpaused return mStarted; } bool LTimer::isPaused(){ //Timer is running and paused return mPaused && mStarted; } class fighter { public: SDL_Surface * sprite; SDL_Rect og;//rectangle of og image SDL_Rect target;//where I want to place the image SDL_Rect attackBox;//where I want to place the image SDL_Texture * fImage; int framesElapsed=0; int currentFrame=1; int framesMax; int framesHold; struct character buffer; bool dead=false; bool isAttacking=false; bool attackPress=true; std::string lastKey; int jumpArc=0; int jumpH; int speed; int health=100; SDL_Renderer * renderer; int frameWidth; fighter(struct character player,SDL_Renderer * renderer1){ framesMax=player.framesMax; framesHold=player.framesHold; buffer=player; speed=buffer.speed; jumpH=buffer.jumpH; sprite = IMG_Load((player.imageSrc).c_str());//loading an image og.x = buffer.offset; og.y = 0; frameWidth=(sprite->w/framesMax); if (sprite->w%framesMax!=0) frameWidth++; og.w = frameWidth-buffer.offset; og.h = sprite->h; attackBox.x = player.attackStats.x; attackBox.y = player.attackStats.y; attackBox.w = player.attackStats.width; attackBox.h = player.attackStats.height; target.x = player.position[0]; target.y = player.position[1]; target.w = og.w; target.h = buffer.height; renderer=renderer1; fImage=SDL_CreateTextureFromSurface(renderer,sprite); } void draw(){ SDL_DestroyTexture(fImage);//memory leak prevention target.x=buffer.position[0]; target.y=buffer.position[1]; fImage = SDL_CreateTextureFromSurface(renderer, sprite);//rendering the sprite SDL_RenderCopy(renderer, fImage, &og, &target);//placing the sprite } void attack(std::string direction=""){ switchSprite(4,direction); if (direction=="") attackBox.x=target.x+buffer.attackStats.x; else attackBox.x=target.x+target.w-buffer.attackStats.x-buffer.attackStats.width; attackBox.w=buffer.attackStats.width; attackBox.y=target.y+buffer.attackStats.y; attackBox.h=buffer.attackStats.height; isAttacking=true; } void takeHit(std::string direction=""){ health-=20; if (health<=0) switchSprite(6,direction); else switchSprite(5,direction); } void animateFrames(float timeStep){ if (timeStep*100>=.6){ og.x = currentFrame * frameWidth + buffer.offset; framesElapsed++; if (framesElapsed%framesHold==0){ if (currentFrame<framesMax-1){ currentFrame++; } else { currentFrame=0; } } } } void update(float timeStep){ draw(); if (!dead) animateFrames(timeStep); if ((buffer.imageSrc==buffer.sprites.death.imageSrc||buffer.imageSrc==buffer.sprites.death.backwardsImg)&&buffer.position[1]==479-target.h) return; buffer.position[1] +=buffer.velocity[1]*timeStep*100; //border detection if (target.x+target.w+buffer.velocity[0]>width) buffer.position[0]=width-target.w; else if (target.x+buffer.velocity[0]<0) buffer.position[0]=0; else buffer.position[0] +=buffer.velocity[0]*timeStep*100; //gravity detection if (target.y+target.h+buffer.velocity[1]>=479){ buffer.velocity[1]=0; buffer.position[1]=479-target.h; if (buffer.velocity[0]==0) jumpArc=0; } else { buffer.velocity[1]+=gravity; } } void swapper(spriteTemplate currentSprite,std::string direction=""){ if (direction=="backwards") buffer.imageSrc=currentSprite.backwardsImg; else buffer.imageSrc=currentSprite.imageSrc; SDL_FreeSurface(sprite); framesMax=currentSprite.framesMax; framesHold=currentSprite.framesHold; buffer.height=currentSprite.scales.height; buffer.width=currentSprite.scales.width; buffer.offset=currentSprite.offset; target.h=buffer.height; target.w=buffer.width; sprite = IMG_Load((buffer.imageSrc).c_str()); og.x=currentSprite.offset; og.y=0; frameWidth=(sprite->w/framesMax); if (sprite->w%framesMax!=0) frameWidth++; og.w = frameWidth-currentSprite.offset; og.h = sprite->h; currentFrame=0; framesElapsed=0; if (target.y+target.h>=479) buffer.position[1]-=target.y+target.h-479; } std::string switchSprite(int pos,std::string direction=""){ if (dead) return ""; if (buffer.imageSrc==buffer.sprites.death.imageSrc||buffer.imageSrc==buffer.sprites.death.backwardsImg) { if (currentFrame==buffer.sprites.death.framesMax-1) dead=true; return ""; } if ((buffer.imageSrc==buffer.sprites.takeHit.imageSrc||buffer.imageSrc==buffer.sprites.takeHit.backwardsImg)&¤tFrame<buffer.sprites.takeHit.framesMax-1) return ""; if ((buffer.imageSrc==buffer.sprites.attack1.imageSrc||buffer.imageSrc==buffer.sprites.attack1.backwardsImg)&¤tFrame==buffer.sprites.attack1.framesMax-1) isAttacking=false; if ((buffer.imageSrc==buffer.sprites.attack1.imageSrc||buffer.imageSrc==buffer.sprites.attack1.backwardsImg)&¤tFrame<buffer.sprites.attack1.framesMax-1) return ""; switch (pos){ case 0: if (buffer.imageSrc!=buffer.sprites.idle.imageSrc&&direction==""||(buffer.imageSrc !=buffer.sprites.idle.backwardsImg&&direction=="backwards")) swapper(buffer.sprites.idle,direction); break; case 1: if (buffer.imageSrc!=buffer.sprites.run.imageSrc&&direction==""||(buffer.imageSrc !=buffer.sprites.run.backwardsImg&&direction=="backwards")) swapper(buffer.sprites.run,direction); break; case 2: if (buffer.imageSrc!=buffer.sprites.jump.imageSrc&&direction==""||(buffer.imageSrc !=buffer.sprites.jump.backwardsImg&&direction=="backwards")) swapper(buffer.sprites.jump,direction); break; case 3: if (buffer.imageSrc!=buffer.sprites.fall.imageSrc&&direction==""||(buffer.imageSrc !=buffer.sprites.fall.backwardsImg&&direction=="backwards")) swapper(buffer.sprites.fall,direction); break; case 4: if (buffer.imageSrc!=buffer.sprites.attack1.imageSrc&&direction==""||(buffer.imageSrc !=buffer.sprites.attack1.backwardsImg&&direction=="backwards")) swapper(buffer.sprites.attack1,direction); break; case 5: if (buffer.imageSrc!=buffer.sprites.takeHit.imageSrc&&direction==""||(buffer.imageSrc !=buffer.sprites.takeHit.backwardsImg&&direction=="backwards")) swapper(buffer.sprites.takeHit,direction); break; case 6: if (buffer.imageSrc!=buffer.sprites.death.imageSrc&&direction==""||(buffer.imageSrc !=buffer.sprites.death.backwardsImg&&direction=="backwards")) swapper(buffer.sprites.death,direction); break; } return ""; } }; bool rectangleCollision(SDL_Rect rect1,SDL_Rect rect2){ return ((rect1.x+rect1.w>=rect2.x&&rect1.x+rect1.w<=rect2.x+rect2.w)||(rect1.x>=rect2.x&&rect1.x<=rect2.x+rect2.w))&&((rect1.y+rect1.h>=rect2.y&&rect1.y+rect1.h<=rect2.y+rect2.h)||(rect1.y>=rect2.y&&rect1.y<=rect2.y+rect2.h)); } int timerValue=60; unsigned __stdcall decreaseTimer(void * data){ int *tptr=&timerValue; if (*tptr>0&&!end){ SDL_Delay(1000); *tptr=timerValue-1; decreaseTimer(data); } return 0; } int main(int argc,char *argv[]){ bool quit = false; SDL_Event event; //initializing everything SDL_Init( SDL_INIT_EVERYTHING ); IMG_Init(IMG_INIT_PNG); IMG_Init(IMG_INIT_JPG); TTF_Init(); SDL_Window * window = SDL_CreateWindow("Fighting Game",SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, 0);//creating a window SDL_Surface * icon=IMG_Load("penisforeskinicon.JPG");//the tab icon SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);//creating the renderer SDL_Texture * texture;//rendering the background SDL_Rect container;//the container for health bars and timer TTF_Font* Sans = TTF_OpenFont("The Wild Breath of Zelda.otf", 24);//the font SDL_Color White = {255, 255, 255}; std::string screen="menu";//the string that stores the current screen SDL_Rect playButton;//menu rect playButton.x=80; playButton.w=200; playButton.y=100; playButton.h=100; SDL_Rect credit; credit.x=80; credit.w=900; credit.y=playButton.y+playButton.h+20; credit.h=120; //select screen rects and select screen stuff SDL_Surface *portraits[2]={IMG_Load("dracPortrait.PNG"),IMG_Load("richardPortrait.PNG")}; SDL_Texture *portraitTextures[2]={SDL_CreateTextureFromSurface(renderer, portraits[0]),SDL_CreateTextureFromSurface(renderer, portraits[1])}; SDL_Rect backButton; backButton.x=80; backButton.w=140; backButton.y=50; backButton.h=100; SDL_Rect characterBox[2]; characterBox[0].x=405; characterBox[0].y=205; characterBox[0].w=50; characterBox[0].h=50; SDL_Rect characters[2]; characters[0].x=400; characters[0].y=200; characters[0].w=60; characters[0].h=60; for (int i=1,x=0;i<2;i++,x+=10){ characters[i].x=characters[i-1].x+characters[i-1].w+10; characters[i].y=200; characters[i].w=60; characters[i].h=60; characterBox[i].x=characters[i-1].x+characters[i-1].w+15; characterBox[i].y=205; characterBox[i].w=50; characterBox[i].h=50; } //setting the container properties container.w=800; container.h=60; container.x=(width/2)-(container.w/2); container.y=10; //the invidual healthbar and timer stuff SDL_Rect healthBar1; SDL_Rect healthBar2; SDL_Rect healthBarBack1; SDL_Rect healthBarBack2; SDL_Rect timer; healthBarBack1.w=360; healthBarBack1.x=container.x+5; healthBarBack1.y=container.y+5; healthBarBack1.h=50; healthBarBack2.w=360; healthBarBack2.x=container.x+5+healthBarBack1.w+70; healthBarBack2.y=container.y+5; healthBarBack2.h=50; healthBar1.w=355; healthBar1.x=healthBarBack1.x+5; healthBar1.y=healthBarBack1.y+5; healthBar1.h=40; healthBar2.w=355; healthBar2.x=container.x+5+healthBarBack1.w+70; healthBar2.y=healthBarBack2.y+5; healthBar2.h=40; timer.w=70; timer.h=60; timer.x=container.x+5+healthBarBack1.w; timer.y=container.y; SDL_Rect endMessage; //create a rect endMessage.x = width/2 - 300/2; //controls the rect's x coordinate endMessage.y = height/2 - 300/2; // controls the rect's y coordinte endMessage.w = 300; // controls the width of the rect endMessage.h = 300; // controls the height of the rect SDL_SetWindowIcon(window, icon);//setting the window SDL_Event windowEvent; int xMouse=0, yMouse=0;//I have absolutely no fucking idea what I'm doing fighter * player=NULL;//initializing the fighters, gonna redo this later so you can select your fighter fighter *enemy=NULL; LTimer stepTimer; //starting the timer, gotta move this when I do the character select shit int *tptr=&timerValue; //the while loop for the game while (true){ if (SDL_PollEvent(&windowEvent)){ if (SDL_QUIT==windowEvent.type){ break; } } //menu screen if (screen=="menu"){ SDL_Surface * image = IMG_Load("background.png");//loading the background image SDL_Surface* play = TTF_RenderText_Solid(Sans, "PLAY", White); SDL_Texture* Message = SDL_CreateTextureFromSurface(renderer, play); SDL_Surface* credits = TTF_RenderText_Solid(Sans, "Credit to pkmarie04 and nacho_cheeze for sprites", White); SDL_Texture* credMessage = SDL_CreateTextureFromSurface(renderer, credits); if(windowEvent.type == SDL_MOUSEMOTION) SDL_GetMouseState(&xMouse,&yMouse); if ((xMouse<=playButton.x+playButton.w&&xMouse>=playButton.x)&&(yMouse<=playButton.y+playButton.h&&yMouse>=playButton.y)) SDL_FillRect(image,&playButton,0xFF0000FF); texture = SDL_CreateTextureFromSurface(renderer, image);//rendering the background SDL_RenderCopy(renderer, texture, NULL, NULL);//placing the background SDL_RenderCopy(renderer, Message, NULL, &playButton); SDL_RenderCopy(renderer, credMessage, NULL, &credit); SDL_RenderPresent(renderer); SDL_RenderClear(renderer);//might change this later, currently used so healthbar rects render properly SDL_FreeSurface(play); SDL_DestroyTexture(Message); SDL_FreeSurface(credits); SDL_DestroyTexture(credMessage); SDL_FreeSurface(image); SDL_DestroyTexture(texture); if(windowEvent.type == SDL_MOUSEBUTTONDOWN) { if (windowEvent.button.button==SDL_BUTTON_LEFT&&((xMouse<=playButton.x+playButton.w&&xMouse>=playButton.x)&&(yMouse<=playButton.y+playButton.h&&yMouse>=playButton.y))) { screen="select"; xMouse=0; yMouse=0; } } } //select screen if (screen=="select"){ SDL_Surface * image = IMG_Load("background.png");//loading the background image if(windowEvent.type == SDL_MOUSEMOTION) SDL_GetMouseState(&xMouse,&yMouse); if ((xMouse<=backButton.x+backButton.w&&xMouse>=backButton.x)&&(yMouse<=backButton.y+backButton.h&&yMouse>=backButton.y)) SDL_FillRect(image,&backButton,0xFF0000FF); SDL_FillRects(image,characters,2,0xFFF00000); texture = SDL_CreateTextureFromSurface(renderer, image);//rendering the background SDL_Surface* back = TTF_RenderText_Solid(Sans, "BACK", White); SDL_Texture* Message = SDL_CreateTextureFromSurface(renderer, back); SDL_RenderCopy(renderer, texture, NULL, NULL);//placing the background SDL_RenderCopy(renderer, Message, NULL, &backButton);//placing the text for the back button for (int i=0;i<t2;i++){ SDL_RenderCopy(renderer, portraitTextures[i], NULL, &characterBox[i]); } SDL_RenderPresent(renderer); SDL_RenderClear(renderer);//might change this later, currently used so healthbar rects render properly SDL_FreeSurface(image); SDL_DestroyTexture(texture); SDL_FreeSurface(back); SDL_DestroyTexture(Message); if(windowEvent.type == SDL_MOUSEBUTTONDOWN) { if (windowEvent.button.button==SDL_BUTTON_LEFT&&((xMouse<=backButton.x+backButton.w&&xMouse>=backButton.x)&&(yMouse<=backButton.y+backButton.h&&yMouse>=backButton.y))) { screen="menu"; xMouse=0; yMouse=0; } if (windowEvent.button.button==SDL_BUTTON_LEFT&&((xMouse<=characters[0].x+characters[0].w&&xMouse>=characters[0].x)&&(yMouse<=characters[0].y+characters[0].h&&yMouse>=characters[0].y))) { if (player==NULL) player=new fighter(Dracaena,renderer); else enemy=new fighter(Dracaena,renderer); } if (windowEvent.button.button==SDL_BUTTON_LEFT&&((xMouse<=characters[1].x+characters[1].w&&xMouse>=characters[1].x)&&(yMouse<=characters[1].y+characters[1].h&&yMouse>=characters[1].y))) { if (player==NULL) player=new fighter(Richard,renderer); else enemy=new fighter(Richard,renderer); } if (player!=NULL&&enemy!=NULL) { screen="game"; unsigned threadID; (HANDLE)_beginthreadex(NULL, 0, &decreaseTimer, (void*)tptr, 0, &threadID); } } } //the actual fighting game code if (screen=="game"){ SDL_Surface * image = IMG_Load("background.png");//loading the background image //this code is so they don't go infinitely in whatever direction they started in player->buffer.velocity[0]=0; enemy->buffer.velocity[0]=0; switch(windowEvent.type){ case SDL_KEYDOWN: switch (windowEvent.key.keysym.sym){ case SDLK_a: keys.a.pressed=true; player->lastKey='a'; break; case SDLK_d: keys.d.pressed=true; player->lastKey='d'; break; case SDLK_w: if (player->buffer.velocity[1]==0) player->buffer.velocity[1]=-player->jumpH; break; case SDLK_SPACE: if (enemy->target.x+enemy->target.w>player->target.x+player->target.w) player->attack(); else player->attack("backwards"); player->attackPress=false; //SDL_FillRect(image,&player->attackBox,0xFF0000FF); break; case SDLK_RIGHT: keys.ArrowRight.pressed=true; enemy->lastKey="ArrowRight"; break; case SDLK_LEFT: keys.ArrowLeft.pressed=true; enemy->lastKey="ArrowLeft"; break; case SDLK_UP: if (enemy->buffer.velocity[1]==0){ enemy->buffer.velocity[1]=-enemy->jumpH; } break; case SDLK_DOWN: if (player->target.x+player->target.w>enemy->target.x+enemy->target.w) enemy->attack(); else enemy->attack("backwards"); enemy->attackPress=false; //SDL_FillRect(image,&enemy->attackBox,0xFF0000FF); break; } break; case SDL_KEYUP: switch (windowEvent.key.keysym.sym){ case SDLK_a: keys.a.pressed=false; break; case SDLK_d: keys.d.pressed=false; break; case SDLK_SPACE: player->attackPress=true; break; case SDLK_RIGHT: keys.ArrowRight.pressed=false; break; case SDLK_LEFT: keys.ArrowLeft.pressed=false; break; case SDLK_DOWN: enemy->attackPress=true; break; } break; } //player movement if (keys.a.pressed&&player->lastKey=="a"&&player->buffer.imageSrc!=player->buffer.sprites.takeHit.imageSrc&&player->buffer.velocity[1]==0) { player->buffer.velocity[0]=-player->speed; player->jumpArc=-player->speed; player->switchSprite(1,"backwards"); } else if (keys.d.pressed&&player->lastKey=="d"&&player->buffer.imageSrc!=player->buffer.sprites.takeHit.imageSrc&&player->buffer.velocity[1]==0) { player->buffer.velocity[0]=player->speed; player->jumpArc=player->speed; player->switchSprite(1); } if (player->buffer.velocity[1]<0){ if (player->jumpArc!=0) player->buffer.velocity[0]=player->jumpArc; if ((enemy->target.x+enemy->target.w>player->target.x+player->target.w&&player->buffer.velocity[0]==0)||player->buffer.velocity[0]>0) player->switchSprite(2); else player->switchSprite(2,"backwards"); } else if (player->buffer.velocity[1]>0){ if (player->jumpArc!=0) player->buffer.velocity[0]=player->jumpArc; if ((enemy->target.x+enemy->target.w>player->target.x+player->target.w&&player->buffer.velocity[0]==0)||player->buffer.velocity[0]>0) player->switchSprite(3); else player->switchSprite(3,"backwards"); } else if (player->buffer.velocity[0]==0&&player->buffer.velocity[1]==0){ if (enemy->target.x+enemy->target.w>player->target.x+player->target.w) player->switchSprite(0); else player->switchSprite(0,"backwards"); } //enemy movement if (keys.ArrowLeft.pressed&&enemy->lastKey=="ArrowLeft"&&enemy->buffer.imageSrc!=enemy->buffer.sprites.takeHit.imageSrc&&enemy->buffer.velocity[1]==0) { enemy->buffer.velocity[0]=-enemy->speed; enemy->jumpArc=-enemy->speed; enemy->switchSprite(1,"backwards"); } else if (keys.ArrowRight.pressed&&enemy->lastKey=="ArrowRight"&&enemy->buffer.imageSrc!=enemy->buffer.sprites.takeHit.imageSrc&&enemy->buffer.velocity[1]==0) { enemy->buffer.velocity[0]=enemy->speed; enemy->jumpArc=enemy->speed; if (enemy->buffer.velocity[1]==0){ enemy->switchSprite(1); } } if (enemy->buffer.velocity[1]<0){ if (enemy->jumpArc!=0) enemy->buffer.velocity[0]=enemy->jumpArc; if ((player->target.x+player->target.w>enemy->target.x+enemy->target.w&&enemy->buffer.velocity[0]==0)||enemy->buffer.velocity[0]>0) enemy->switchSprite(2); else enemy->switchSprite(2,"backwards"); } else if (enemy->buffer.velocity[1]>0){ if (enemy->jumpArc!=0) enemy->buffer.velocity[0]=enemy->jumpArc; if ((player->target.x+player->target.w>enemy->target.x+enemy->target.w&&enemy->buffer.velocity[0]==0)||enemy->buffer.velocity[0]>0) enemy->switchSprite(3); else enemy->switchSprite(3,"backwards"); } else if (enemy->buffer.velocity[0]==0&&enemy->buffer.velocity[1]==0){ if (player->target.x+player->target.w>enemy->target.x+enemy->target.w) enemy->switchSprite(0); else enemy->switchSprite(0,"backwards"); } //collision detection and hitting if (rectangleCollision(player->attackBox,enemy->target)&&player->isAttacking&&player->currentFrame==player->buffer.attackStats.frame-1) { if (enemy->target.x+enemy->target.w>player->target.x+player->target.w) enemy->takeHit("backwards"); else enemy->takeHit(); player->isAttacking=false; healthBar2.w-=71; } if (rectangleCollision(enemy->attackBox,player->target)&&enemy->isAttacking&&enemy->currentFrame==enemy->buffer.attackStats.frame-1) { if (player->target.x+player->target.w>enemy->target.x+enemy->target.w) player->takeHit("backwards"); else player->takeHit(); enemy->isAttacking=false; healthBar1.x+=71; healthBar1.w-=71; } //the ui display stuff SDL_FillRect(image,&healthBarBack1,0); SDL_FillRect(image,&healthBarBack2,0); SDL_FillRect(image,&timer,0xFF0000FF); SDL_FillRect(image,&healthBar1,0xFFF00000); SDL_FillRect(image,&healthBar2,0xFFF00000); //SDL_FillRect(image,&player->target,0xFF0000FF);//hitbox tracking temporary remove later //SDL_FillRect(image,&enemy->target,0xFF0000FF);//hitbox tracking temporary remove later texture = SDL_CreateTextureFromSurface(renderer, image);//rendering the background SDL_RenderCopy(renderer, texture, NULL, NULL);//placing the background //timer display shit SDL_Surface* timerNum = TTF_RenderText_Solid(Sans, std::to_string(timerValue).c_str(), White); SDL_Texture* Message = SDL_CreateTextureFromSurface(renderer, timerNum); SDL_RenderCopy(renderer, Message, NULL, &timer); //frame rate independence shit float timeStep=stepTimer.getTicks()/1000.f; //updating the fighters player->update(timeStep); enemy->update(timeStep); //Restart step timer stepTimer.start(); SDL_RenderPresent(renderer); SDL_RenderClear(renderer);//might change this later, currently used so healthbar rects render properly SDL_FreeSurface(image); SDL_DestroyTexture(texture); SDL_FreeSurface(timerNum); SDL_DestroyTexture(Message); //finishing the game stuff if (player->health<=0||enemy->health<=0||timerValue==0){ if ((player->buffer.imageSrc==player->buffer.sprites.death.imageSrc||player->buffer.imageSrc==player->buffer.sprites.death.backwardsImg)&&player->currentFrame==player->buffer.sprites.death.framesMax-1){ delete player; delete enemy; player=NULL; enemy=NULL; *tptr=60; healthBar1.w=355; healthBar1.x=healthBarBack1.x+5; healthBar1.y=healthBarBack1.y+5; healthBar1.h=40; healthBar2.w=355; healthBar2.x=container.x+5+healthBarBack1.w+70; healthBar2.y=healthBarBack2.y+5; healthBar2.h=40; SDL_Delay(1500); screen = "select"; } else if ((enemy->buffer.imageSrc==enemy->buffer.sprites.death.imageSrc||enemy->buffer.imageSrc==enemy->buffer.sprites.death.backwardsImg)&&enemy->currentFrame==enemy->buffer.sprites.death.framesMax-1){ delete player; delete enemy; player=NULL; enemy=NULL; *tptr=60; healthBar1.w=355; healthBar1.x=healthBarBack1.x+5; healthBar1.y=healthBarBack1.y+5; healthBar1.h=40; healthBar2.w=355; healthBar2.x=container.x+5+healthBarBack1.w+70; healthBar2.y=healthBarBack2.y+5; healthBar2.h=40; SDL_Delay(1500); screen = "select"; } } } } //cleanup SDL_DestroyTexture(texture); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); TTF_Quit(); IMG_Quit(); SDL_Quit(); return 0; }
This is the code for the fighting game, although this was written in C++, the JavaScript version is playable on the "Games" tab. This was written in C++ with SDL2 It's basically the same as the one on the "Games" tab, however to give you the rundown, it has its own animation system, a proper timer, character select, and all the basic mechanisms behind fighting games. This was fun to make as I had to work with my friends to implement the sprite work and characters. Some days I muse on improving on it and publishing it as a full-fledged game, but that's perhaps for another time
#include <LiquidCrystal.h> String buffer=""; String evaluate(String eq,int start, int end){ int index=0; String ptr[100]; String buffer=""; double answer=0; for (int i=0;i<eq.length();i++){ if (eq[i]!='+'&&eq[i]!='-'&&eq[i]!='*'&&eq[i]!='/') { if (buffer[buffer.length()-1]=='.'&&eq[i]=='.') return "Syntax Error"; buffer+=eq[i]; } else { ptr[index]=buffer; index++; String s(eq[i]); ptr[index]=s; index++; buffer=""; } } ptr[index]=buffer; index++; String nextPos=""; String swapper=ptr[0]; if (ptr[0]!="-") { for (int k = index; k > 0; k--){ ptr[k]=ptr[k-1]; } ptr[0]="+"; index++; } for (int i=0;i<index;i++){ if (ptr[i]=="/"||ptr[i]=="*"){ String temp; if (ptr[i]=="/") temp=String(ptr[i-1].toFloat()/ptr[i+1].toFloat()); else temp=String(ptr[i-1].toFloat()*ptr[i+1].toFloat()); for(int k = i+1,c=i; k < index; k++,c++) ptr[c] = ptr[k]; index--; for(int k = i+1,c=i; k < index; k++,c++) ptr[c] = ptr[k]; index--; ptr[i-1]=temp; i--; } } for (int i=0;i<index;i++){ if (ptr[i]=="+"||ptr[i]=="-"){ if (ptr[i]=="+") answer+=ptr[i+1].toFloat(); else answer-=ptr[i+1].toFloat(); i++; } } return String(answer); } bool test(int pin){ if (digitalRead(pin)==HIGH) return true; return false; } LiquidCrystal lcd(6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); void setup() { lcd.begin(16, 2); } bool activate=false; void loop() { if (test(2)&&!test(3)&&!test(4)&&!test(5)) { buffer+=String('1'); delay(160); lcd.clear(); lcd.print(buffer); } if (!test(2)&&test(3)&&!test(4)&&!test(5)) { buffer+=String('2'); delay(160); lcd.clear(); lcd.print(buffer); } if (test(2)&&test(3)&&!test(4)&&!test(5)) { buffer+=String('3'); delay(160); lcd.clear(); lcd.print(buffer); } if (!test(2)&&!test(3)&&test(4)&&!test(5)) { buffer+=String('4'); delay(160); lcd.clear(); lcd.print(buffer); } if (test(2)&&!test(3)&&test(4)&&!test(5)) { buffer+=String('5'); delay(160); lcd.clear(); lcd.print(buffer); } if (!test(2)&&test(3)&&test(4)&&!test(5)) { buffer+=String('6'); delay(160); lcd.clear(); lcd.print(buffer); } if (test(2)&&test(3)&&test(4)&&!test(5)) { buffer+=String('7'); delay(160); lcd.clear(); lcd.print(buffer); } if (!test(2)&&!test(3)&&!test(4)&&test(5)) { buffer+=String('8'); delay(160); lcd.clear(); lcd.print(buffer); } if (test(2)&&!test(3)&&!test(4)&&test(5)) { buffer+=String('9'); delay(160); lcd.clear(); lcd.print(buffer); } if (!test(2)&&test(3)&&!test(4)&&test(5)) { buffer+=String('0'); delay(160); lcd.clear(); lcd.print(buffer); } if (test(2)&&test(3)&&!test(4)&&test(5)) { buffer+=String('+'); delay(160); lcd.clear(); lcd.print(buffer); } if (!test(2)&&!test(3)&&test(4)&&test(5)) { buffer+=String('-'); delay(160); lcd.clear(); lcd.print(buffer); } if (test(2)&&!test(3)&&test(4)&&test(5)) { buffer+=String('*'); delay(160); lcd.clear(); lcd.print(buffer); } if (!test(2)&&test(3)&&test(4)&&test(5)) { buffer+=String('/'); delay(160); lcd.clear(); lcd.print(buffer); } if (test(2)&&test(3)&&test(4)&&test(5)&&buffer!="") { activate=true; } if (activate&&buffer!="") { String temp=evaluate(buffer,0,buffer.length()); activate=false; buffer=""; delay(160); lcd.setCursor(0, 2); lcd.print(temp); } }
This is a calculator I made using arduino. Yes a physical calculator I built. I used diodes to make a binary input system to save pin space. This is more of a foray into hardware and more hardware based projects. Below is a photo of the calculator working, I was pretty proud of myself when it all came together even though a calculator has technically been done before