Simppeli retrotyylinen matopeli. Toimii esimerkkinä WinAPI:n ja GDI:n käytöstä PL/I:n kanssa touhutessa.
valmis binääri -ja lähdekoodipaketti löytyypi tällä hetkellä: pli_snake.zip
*PROCESS MARGINS(1,160) LANGLVL(SAA2) pp(macro); *PROCESS LIMITS(EXTNAME(100) fixedbin(63) fixeddec(31) name(100) ); *PROCESS NOT('ª^') DFT(BYVALUE); *PROCESS INCLUDE (EXT('CPY','INC')); Snake: package; /* Include win32 stuff */ %include winbase; %include wingdi; %include winuser; %include commctrl; %include snake; /* application include file */ dcl MAP_SIZE type INT value (24); dcl TILE_SIZE type INT value (16); dcl CRASH_ADD type INT value (4); dcl ID_TIMER type INT value (1); dcl TIMER_DELAY type INT value (180); dcl (addr, binvalue, mod, iand, inot, ior, length, null, sysnull, size, time, random) builtin; /* Prototypes and constants*/ dcl 1 point_type based, 2 x type INT, 2 y type INT; dcl 1 ZERO, 2 x type INT value (0), 2 y type INT value (0); dcl 1 LEFT, 2 x type INT value (-1), 2 y type INT value (0); dcl 1 RIGHT, 2 x type INT value (1), 2 y type INT value (0); dcl 1 UP, 2 x type INT value (0), 2 y type INT value (-1); dcl 1 DOWN, 2 x type INT value (0), 2 y type INT value (1); define ordinal MAP_ID (EMPTY, SNAKE, FOOD, CRASH); dcl IDC_MAIN_STATUS type INT value (103); /******************************************************************************************************/ /* global variables */ dcl g_hbmBuffer type HBITMAP init (sysnull()); dcl g_hGreenPen type HPEN; dcl g_hRedPen type HPEN; dcl g_hYellowPen type HPEN; dcl g_hGreenBrush type HBRUSH; dcl g_hRedBrush type HBRUSH; dcl g_hYellowBrush type HBRUSH; dcl g_hFont type HFONT; dcl g_map (0:MAP_SIZE - 1, 0:MAP_SIZE - 1) type INT; dcl g_snake (0:((MAP_SIZE - 1)*(MAP_SIZE - 1))) like point_type; dcl g_len_snake type INT; dcl g_dir like point_type; dcl g_ndir like point_type; dcl g_food like point_type; dcl g_crash like point_type; dcl g_leave_it type BOOL; dcl g_crashed type BOOL; dcl g_szScore char (12) varz init (' SCORE: '); dcl g_score pic '9999' init ('0000'); dcl wndclass type WNDCLASSEX; dcl hInstance type HINSTANCE; /******************************************************************************************************/ /* main procedure */ WinMain: proc (hInstance, hPrevInstance, szCmdLine, iCmdShow) returns(type INT) options (winmain); dcl hInstance type HINSTANCE; dcl hPrevInstance type HINSTANCE; dcl szCmdLine ptr; dcl iCmdShow type INT; /* local variables */ dcl hwnd type HWND; dcl msg type MSG; dcl szAppName char (50) varz init ('Snake'); dcl szAppTitle char (50) varz init ('Simple Snake Game in Windows PL/I!'); /* initialize */ wndclass.cbSize = size(wndclass); wndclass.style = ior(CS_HREDRAW, CS_VREDRAW); wndclass.lpfnWndProc = WinProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hCursor = LoadCursor(sysnull(), pli_b2z(binvalue(IDC_ARROW))); wndclass.hIcon = LoadIcon(hInstance, pli_b2z(IDI_BALL)); wndclass.hbrBackground = GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = sysnull(); wndclass.lpszClassName = addr(szAppName); wndclass.hIconSm = LoadIcon(hInstance, pli_b2z(IDI_SBALL)); /* register class */ call RegisterClassEx (wndclass); /* Create a window */ hwnd = CreateWindow(szAppName, /* window class name */ szAppTitle, /* window caption */ ior(WS_OVERLAPPED, WS_SYSMENU), /* window style */ CW_USEDEFAULT, /* x pos */ CW_USEDEFAULT, /* y pos */ 0, /* x size */ 0, /* y size */ sysnull(), /* parent window hand*/ sysnull(), /* window menu hand */ hInstance, /* pgm instance hand */ sysnull() ); /* creation params */ /* Show the window */ call ShowWindow(hwnd, iCmdShow) ; call UpdateWindow(hwnd); /* Message Loop */ do while (GetMessage(msg, sysnull(), 0, 0) ^= 0); call TranslateMessage(msg); call DispatchMessage(msg); end; /* of do */ return (msg.wParam); end WinMain; /* of program */ /******************************************************************************************************/ /* Window procedure */ WinProc: proc (hwnd, msg, mp1, mp2) options(byvalue, linkage (stdcall)) returns (type LRESULT); dcl hwnd type HWND; dcl msg type UINT; dcl mp1 type WPARAM; dcl mp2 type LPARAM; /* local variables */ dcl hdc type HDC; dcl hStatus type HWND; dcl ps type PAINTSTRUCT; dcl (rectl, rcStatus) type RECT; dcl lfHeight type INT; dcl iStatusHeight type INT; dcl szScore char (20) varz; select (msg); when (WM_CREATE) do; /* Create statusbar for score info */ hStatus = CreateWindowEx(0, STATUSCLASSNAME, '', ior(WS_CHILD, WS_VISIBLE), 0, 0, 0, 0, hwnd, cast(:HMENU, IDC_MAIN_STATUS:), hInstance, sysnull()); call GetWindowRect(hStatus, rcStatus); iStatusHeight = rcStatus.bottom - rcStatus.top; call ResizeClient(hwnd, MAP_SIZE * TILE_SIZE, MAP_SIZE * TILE_SIZE + iStatusHeight); call SendMessage(hStatus, WM_SIZE, 0, 0); szScore = g_szScore || g_score; call SetWindowText(hStatus, szScore); /* Init pens and brushes */ g_hGreenPen = CreatePen(PS_SOLID, 1, RGB(0,255,0)); g_hGreenBrush = CreateSolidBrush(RGB(0,255,0)); g_hRedPen = CreatePen(PS_SOLID, 1, RGB(255,0,0)); g_hRedBrush = CreateSolidBrush(RGB(255,0,0)); g_hYellowPen = CreatePen(PS_SOLID, 1, RGB(255,255,0)); g_hYellowBrush = CreateSolidBrush(RGB(255,255,0)); /* Init game over font */ hdc = GetDC(sysnull()); lfHeight = -MulDiv(32, GetDeviceCaps(hdc, LOGPIXELSY), 72); call ReleaseDC(sysnull(), hdc); g_hFont = CreateFont(lfHeight, 0, 0, 0, 0, TRUE, 0, 0, 0, 0, 0, 0, 0, 'Times New Roman'); /* Init and start the game */ call InitSnake; call SetTimer(hwnd, ID_TIMER, TIMER_DELAY); end; /* of when */ when (WM_KEYDOWN) select (mp1); when (VK_LEFT) g_ndir = (LEFT); when (VK_RIGHT) g_ndir = (RIGHT); when (VK_UP) g_ndir = (UP); when (VK_DOWN) g_ndir = (DOWN); when (VK_SPACE) if g_crashed = TRUE then do; call InitSnake; call SetTimer(hwnd, ID_TIMER, TIMER_DELAY); end; end; /* of select (mp1) */ when (WM_TIMER) do; /* Update game and force redraw */ call UpdateSnake; call GetClientRect(hwnd, rectl); hStatus = GetDlgItem(hwnd, IDC_MAIN_STATUS); call GetWindowRect(hStatus, rcStatus); iStatusHeight = rcStatus.bottom - rcStatus.top; rectl.bottom = rectl.bottom - iStatusHeight; call InvalidateRect(hwnd, rectl, FALSE); szScore = g_szScore || g_score; call SetWindowText(hStatus, szScore); if g_crashed = TRUE then call KillTimer(hwnd, ID_TIMER); end; /* of when */ when (WM_PAINT) do; hdc = BeginPaint(hwnd, ps); call GetClientRect(hwnd, rectl); hStatus = GetDlgItem(hwnd, IDC_MAIN_STATUS); call GetWindowRect(hStatus, rcStatus); iStatusHeight = rcStatus.bottom - rcStatus.top; rectl.bottom = rectl.bottom - iStatusHeight; if g_hbmBuffer = sysnull() then g_hbmBuffer = CreateCompatibleBitmap(hdc, rectl.right, rectl.bottom); call DrawSnake(hdc, rectl, g_hbmBuffer); call EndPaint(hwnd, ps); end; /* of when */ when (WM_DESTROY) do; /* Terminate the application */ call KillTimer(hwnd, ID_TIMER); /* Delete used GDI objects */ call DeleteObject(g_hGreenPen); call DeleteObject(g_hRedPen); call DeleteObject(g_hYellowPen); call DeleteObject(g_hGreenBrush); call DeleteObject(g_hRedBrush); call DeleteObject(g_hYellowBrush); call DeleteObject(g_hFont); call DeleteObject(g_hbmBuffer); call PostQuitMessage(0); end; /* of when */ otherwise return (DefWindowProc(hwnd,msg,mp1,mp2)); end; /* of select (msg) */ return (0); end WinProc; /* of procedure */ /******************************************************************************************************/ /* Resize client rectangle */ ResizeClient: proc (hwnd, nWidth, nHeight); dcl hwnd type HWND; dcl (nWidth, nHeight) type INT; dcl (rcClient, rcWindow) type RECT; dcl ptDiff type POINT; call GetClientRect(hwnd, rcClient); call GetWindowRect(hwnd, rcWindow); ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right; ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom; call MoveWindow(hwnd, rcWindow.left, rcWindow.top, nWidth + ptDiff.x, nHeight + ptDiff.y, TRUE); end ResizeClient; /******************************************************************************************************/ /* Init snake procedure */ InitSnake: proc; dcl (i, j) type INT; dcl start like point_type; dcl seed float bin (53) static init (0); if seed = 0 then seed = random(time()); g_score = '0000'; do i = 0 to MAP_SIZE - 1; do j = 0 to MAP_SIZE - 1; g_map (i, j) = binvalue(EMPTY); end; end; g_len_snake = 3; g_dir = (RIGHT); g_ndir = g_dir; start.x = (MAP_SIZE - 1) * random(); start.y = (MAP_SIZE - 1) * random(); do i = 0 to g_len_snake; g_snake(i) = start; end; g_map(start.y, start.x) = binvalue(SNAKE); g_crash = (ZERO); g_leave_it = FALSE; g_crashed = FALSE; g_food.x = (MAP_SIZE - 1) * random(); g_food.y = (MAP_SIZE - 1) * random(); g_map(g_food.y, g_food.x) = binvalue(FOOD); end InitSnake; /******************************************************************************************************/ /* Update snake procedure */ UpdateSnake: proc; dcl i type INT; dcl np like point_type; if (g_dir.x * (-1) ^= g_ndir.x) & (g_dir.y * (-1) ^= g_ndir.y) then g_dir = g_ndir; np = g_snake(g_len_snake) + g_dir; np = mod(np + MAP_SIZE, MAP_SIZE); if g_map(np.y, np.x) = binvalue(SNAKE) then do; g_crashed = TRUE; g_map(np.y, np.x) = binvalue(CRASH); g_crash = np; g_leave_it = TRUE; end; else if g_map(np.y, np.x) = binvalue(FOOD) then do; do loop; g_food.x = (MAP_SIZE - 1) * random(); g_food.y = (MAP_SIZE - 1) * random(); if g_map(g_food.y, g_food.x) = binvalue(EMPTY) then leave; end; g_map(g_food.y, g_food.x) = binvalue(FOOD); g_score += 1; g_leave_it = TRUE; end; if g_leave_it = TRUE then do; g_len_snake += 1; g_leave_it = FALSE; end; else do; g_map(g_snake(0).y, g_snake(0).x) = binvalue(EMPTY); do i = 0 to g_len_snake - 1; g_snake(i) = g_snake(i+1); end; end; g_snake(g_len_snake) = np; g_map(np.y, np.x) = binvalue(SNAKE); end UpdateSnake; /******************************************************************************************************/ /* Draw snake procedure */ DrawSnake: proc (hdc, prc, hbuffer); dcl hdc type HDC; dcl prc type RECT; dcl hbuffer type HBITMAP; /* static variables */ dcl szGameOver char (12) varz static init ('GAME OVER'); /* local variables */ dcl hdcBuffer type HDC; dcl hbmOldBuffer type HBITMAP; dcl hOldPen type HPEN; dcl hOldBrush type HBRUSH; dcl hOldFont type HFONT; dcl i type INT; hdcBuffer = CreateCompatibleDC(hdc); hbmOldBuffer = SelectObject(hdcBuffer, g_hbmBuffer); /* Clear game screen */ call FillRect(hdcBuffer, prc, GetStockObject(WHITE_BRUSH)); /* Draw snake */ hOldPen = SelectObject(hdcBuffer, g_hGreenPen); hOldBrush = SelectObject(hdcBuffer, g_hGreenBrush); do i = 0 to g_len_snake; call Rectangle(hdcBuffer, g_snake(i).x * TILE_SIZE, g_snake(i).y * TILE_SIZE, g_snake(i).x * TILE_SIZE + TILE_SIZE, g_snake(i).y * TILE_SIZE + TILE_SIZE); end; /* Draw food */ call SelectObject(hdcBuffer, g_hRedPen); call SelectObject(hdcBuffer, g_hRedBrush); call Ellipse(hdcBuffer, g_food.x * TILE_SIZE, g_food.y * TILE_SIZE, g_food.x * TILE_SIZE + TILE_SIZE, g_food.y * TILE_SIZE + TILE_SIZE); /* Draw crash image and GAME OVER text if snake crashed */ if g_crashed = TRUE then do; call SelectObject(hdcBuffer, g_hYellowPen); call SelectObject(hdcBuffer, g_hYellowBrush); call Ellipse(hdcBuffer, g_crash.x * TILE_SIZE - CRASH_ADD, g_crash.y * TILE_SIZE - CRASH_ADD, g_crash.x * TILE_SIZE + TILE_SIZE + CRASH_ADD, g_crash.y * TILE_SIZE + TILE_SIZE + CRASH_ADD); hOldFont = SelectObject(hdcBuffer, g_hFont); call SetBkMode(hdcBuffer, TRANSPARENT); call DrawText(hdcBuffer, szGameOver, -1, prc, ior(DT_SINGLELINE, DT_CENTER, DT_VCENTER)); call SelectObject(hdcBuffer, hOldFont); end; /* Blit memory buffer to screen */ call BitBlt(hdc, 0, 0, prc.right, prc.bottom, hdcBuffer, 0, 0, SRCCOPY); /* Clean up and restore default GDI objects */ call SelectObject(hdcBuffer, hOldPen); call SelectObject(hdcBuffer, hOldBrush); call SelectObject(hdcBuffer, hbmOldBuffer); call DeleteDC(hdcBuffer); end DrawSnake; /******************************************************************************************************/ end Snake; /* of package */
Aihe on jo aika vanha, joten et voi enää vastata siihen.