image

Среди ретро-софта есть отдельный вид, называемый игрушки (toys) в отличие от игр (games). Две игрушки, которые сегодня нашел в своем старом архиве, когда-то во времена MS DOS вызывали бурный восторг, может, и сейчас кого-то повеселят :)

А начинающим будет нескучно решить несколько занимательных задач.

У меня менее древняя реализация для Windows (вплоть до XP SP3) на Delphi-7. Источники, к сожалению, не помню.

Первая игрушка называется Noga. Запускаем exe-файл и видим, как по десктопу идет кто-то невидимый, оставляя следы:

image

Вторая игрушка Flip – просто переворачивает десктоп:

image

Устройство очень простое. На стандартую форму помещаем стандартные таймер и список картинок (TimageList). Список содержит картинки ног:

imageimage
(в программах использован bmp-формат, но в habrastorage.org он недопустим)

Интервал таймера выставляем 1000 мсек., свойство Enabled в True. Исходный код почти тривиальный (задача №1 начинающему – самостоятельно разобраться, как он работает).

noga код
unit noga;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, ImgList;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    Image1: TImage;
    ImageList1: TImageList;
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure Image1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    curX,curY,dx, dy : integer;
    lBitmap,rBitmap : tbitmap;
    procedure prepMainWindow;
    procedure drawNogas;
  end;

var
  Form1: TForm1;

implementation
 uses Clipbrd;
{$R *.DFM}

procedure TForm1.prepMainWindow;
var
        h,hMem : HDC;
        w,cl : HWnd;
        xSz,ySz : integer;
        bitmap : TBitmap{HBITMAP};
        bt : HBITMAP;
begin
// decktop capture
  hide;
  w := HWND_DESKTOP;
  h := GetDeviceContext(w);
  xSz :=  GetDeviceCaps(h,HORZRES);
  ySz :=  GetDeviceCaps(h,VERTRES);
  hMem := CreateCompatibleDC (h);

  bitmap := TBitmap.Create;
  bitmap.width := xSz;
  bitmap.height := ySz;
  bt := CreateCompatibleBitmap (h,xSz,ySz);
  SelectObject (hMem,bt{bitmap.Handle});
  StretchBlt (hMem, 0,0, xSz,ySz,
                h, 0,0, xSz,ySz, SRCCOPY);
  show;
  width := xSz;
  height := ySz;
  bitmap.Handle := bt;
  bitmap.HandleType := bmDIB; {(bmDIB, bmDDB)}
  Image1.Picture.Graphic := Bitmap;
  Bitmap.free;
// Left Noga
  lBitmap := TBitmap.Create;
  ImageList1.GetBitmap(0,lBitmap);
  lBitmap.transparent := true;
// Right Noga
  rBitmap := TBitmap.Create;
  ImageList1.GetBitmap(1,rBitmap);
  rBitmap.transparent := true;
// --------------------
  dx := xSz div 2;
  dy := ySz div 20;
  curX := dx;
  curY := ySz -dy;
end;

procedure TForm1.drawNogas;
begin
  messageBeep (mb_Ok);
  Canvas.draw(curX-lBitmap.width,curY,lBitmap);
  curY := curY -2*dy{-lBitmap.height};
  Canvas.draw(curX{+lBitmap.width},curY,rBitmap);
  curY := curY -4*dy;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 prepMainWindow;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
    if curY > 0
     then
       drawNogas
     else
       Timer1.Enabled := false;
end;

procedure TForm1.Image1Click(Sender: TObject);
begin
         Application.Terminate;
end;

end.


Вторая игрушка легко получается из первой:

flip код
unit noga;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    procedure FormCreate(Sender: TObject);
    procedure Image1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    curX,curY,dx, dy : integer;
    lBitmap,rBitmap : tbitmap;
    procedure test;
  end;

var
  Form1: TForm1;

implementation
 uses Clipbrd;
{$R *.DFM}

procedure TForm1.test;
var
        h,hMem : HDC;
        w,cl : HWnd;
        xSz,ySz,x,y : integer;
        bitmap,bitmap2 : TBitmap{HBITMAP};
        bt : HBITMAP;
begin
        hide;
        screen.cursor := crHourGlass;
  w := HWND_DESKTOP;
  h := GetDeviceContext(w);
  xSz :=  GetDeviceCaps(h,HORZRES);
  ySz :=  GetDeviceCaps(h,VERTRES);
  hMem := CreateCompatibleDC (h);

  bitmap := TBitmap.Create;
  bitmap.width := xSz;
  bitmap.height := ySz;
  bt := CreateCompatibleBitmap (h,xSz,ySz);
  SelectObject (hMem,bt{bitmap.Handle});
  StretchBlt (hMem, 0,0, xSz,ySz,
                h, 0,0, xSz,ySz, SRCCOPY);
  width := xSz;
  height := ySz;
 bitmap.Handle := bt;
 bitmap.HandleType := bmDIB; 
bitmap2 := TBitmap.Create;
  bitmap2.width := xSz;
  bitmap2.height := ySz;
  for y:=1 to ySz do
        for x :=1 to xSz do
                bitmap2.Canvas.Pixels [x,y]:=
                bitmap.Canvas.Pixels [xSz-x+1,ySz-y+1];

Image1.Picture.Graphic := Bitmap2;
  show;
  screen.cursor := crDefault;
  Bitmap.free;
  Bitmap2.free;

end;


procedure TForm1.FormCreate(Sender: TObject);
begin
 test;
end;

procedure TForm1.Image1Click(Sender: TObject);
begin
         Application.Terminate;
end;

end.


В заключение еще задачки для начинающих.

Задача №2. С последующими ОС (например, Windows 8.1) приведенный код работать не будет. Нужно переделать. Почитать (Гугл в помощь) и подумать о совместимости ОС Windows.

Примечание. Кто хочет попробовать данные игрушки, но не хочет ставить на диск такую «устаревшую» ОС, как Windows XP, — может поставить ее на виртуальную машину.

Задача №3 (можно объединить с предыдущей). ООП Паскаль Delphi-7 всё еще относительно популярен, но сейчас многие предпочитают другие языки. Переведите код на свой любимый язык под любимую IDE.

Примечание. Стиль кода может быть улучшен. Это можно сделать при переводе.

Задача №4. Объедините приведенные программы в одну, т.е. следы должны появляться на перевернутом десктопе.

Задача №5. Если Вы знакомы с программированием под Linux и/или MacOS – попробуйте портировать.

Задача №6. Попробуйте придумать другие забавные игрушки (toys).

Желаю веселого старого Нового года!

Комментарии (16)


  1. TonyLorencio
    11.01.2019 15:09
    +2

    Переведите код на свой любимый язык под любимую IDE.

    Все-таки в идеальном случае код вообще не должен быть привязан к IDE.


    1. third112 Автор
      11.01.2019 15:21
      -3

      Согласен, что в некоторых случаях м.б. принципиально, чтобы код был не привязан к IDE. В других это не имеет значение. Но для начинающего м.б. проще работать с компонентами (таймер, форма, список картинок и т.д.)

      (BTW Я и не говорю: привязать код к IDE. Работать можно под разными IDE (если они есть) в одном проекте, сохраняя независимость от них кода).


    1. third112 Автор
      11.01.2019 17:24

      TonyLorencio доказательство предъявите?:

      в идеальном случае код вообще не должен быть привязан к IDE


      А то уж больно нелепо звучит в одной фразе.


  1. maxzh83
    11.01.2019 15:44

    В школе делал что-то подобное (но я бы не назвал это «игрушкой»), программа делала снимок экрана, потом разворачивалась на весь экран поверх всех окон, отображая сделанный снимок. Создавалось впечатление, что компьютер завис.


    1. third112 Автор
      11.01.2019 15:51
      -1

      ИМХО если есть практическая цель, нпр., сделать снимок экрана, чтобы сохранить его в файл, то это не игрушка, а инструмент. А если цель посмеяться над испуганным товарищем, то игрушка :)


  1. bvn13
    11.01.2019 15:56
    +1

    А как же «глаза», «пингвин», «снежки» и «котик»?


    1. third112 Автор
      11.01.2019 16:11
      -1

      Глаза видел, другие не помню. Где посмотреть? Они старые?


  1. lleo_aha
    11.01.2019 15:57
    +4

    Задача №7: Давайте удалим этот полезный и информативный пост


  1. vesper-bot
    11.01.2019 16:03

    На некоторых системах Flip неплохо реализуется шорткатом Ctrl+Alt+Down Arrow. Да ещё и остается интерактивным. Чем не игрушка? :)


    1. TonyLorencio
      11.01.2019 16:14

      Это утилита видеодрайвера, насколько я помню.


  1. OlegIn_Geolog
    11.01.2019 16:18

    У нас в моде была довольно жестокая шутка (не игрушка, хотя можно было и написать простенький код, но проще было руками сделать). Вместо стандартной заставки Screensaver ставилась знаменитая картинка с надписью «Теперь питание компьютера можно отключить». Человек уходил на перекур, чай, кофе, возвращался, видел экран, сильно удивлялся, еще сильнее расстраивался по поводу несохраненных данных, но питание выключал.


    1. yar3333
      11.01.2019 16:34

      Из аналогичного — сделать скрин экрана и поставить его картинкой на рабочий стол. После чего спрятать или удалить иконки с рабочего стола :)


  1. Ableness
    11.01.2019 16:40

    Ноги — скукота, а вот овечки были весьма прелестны lurkmore.to/Screenmates


    1. third112 Автор
      11.01.2019 17:19

      Но! Они в GUI, а я про MS DOS. В Офисе и пресловутого Помощника можно рассматривать, как овечку.


  1. stavinsky
    11.01.2019 16:54

    На старых мониках вообще можно было яркость выкрутить.
    А еще есть вот такой сайт. В фул скрине люди пугаются fakeupdate.net
    А в целом не понятно к чему этот информационный пост.


    1. third112 Автор
      11.01.2019 17:03

      А в целом не понятно к чему этот информационный пост.

      К Новому году, Карл :)