Форум программистов

Форум программистов (http://www.programmersforum.ru/index.php)
-   Создание и обсуждение игр (http://www.programmersforum.ru/forumdisplay.php?f=33)
-   -   Уроки по созданию игр для новичков... (http://www.programmersforum.ru/showthread.php?t=1206)
-   -   -   Рип от 19.07.2010 23:20 by DomiNick.

-=DeS=- 07.01.2007 15:38

Уроки по созданию игр для новичков...
 
В этом уроке я научу вас как можно передвигать обьекты по форме с помощью клавиш...
--------------------------
Начнём.
1)Создайте новый проект File> New> Application
2)Теперь киньте на форму объект TShape
3)После этого выбираем в Object TreeView форму (Form1)
4)В Object inspector на вкладке Events ищем свойство OnKeyDown и щёлкаем на него 2 раза.
5)В созданной процедуре пишем код (я рекомендую вам не просто копировать а понять как это работает!)
Цитата:

if key=VK_UP then Shape1.Top:=Shape1.Top-2;
Этот код будет двигат фигуру Shape1 на 2 пиксела вверх!
---------------------------
Попробуйте сами написать движение вниз, вправо, влево...
Позже и это будет показано!

-=DeS=- 12.01.2007 21:52

Урок #2 Двигаем фигуру как хотим!!!
Добавьте в свою программу этот код и ваша фигура будет двигаться по всей форме!
Цитата:

unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;
type
TForm1 = class(TForm)
Shape1: TShape;
procedure FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if key=VK_UP then Shape1.Top:=Shape1.Top-2;
if key=VK_LEFT then Shape1.Left:=Shape1.Left-2;
if key=VK_DOWN then Shape1.Top:=Shape1.Top+2;
if key=VK_RIGHT then Shape1.Left:=Shape1.Left+2;
end;
end.

-=DeS=- 24.01.2007 23:18

Урок №3
--------------------
Как вы уже поняли фигура может двигаться куда попало...даже за пределы формы... а это не очень то и хорошо =)...
Давайте вместе напишем код который будет ограничевать движение фигуры влево и вправо...
---------------------
Попробуйте написать вашу программу вот так:
Код:

unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;
type
  TForm1 = class(TForm)
    Shape1: TShape;
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if( Key = VK_RIGHT ) and ( shape1.Left + shape1.Width <= Form1.ClientWidth-7 ) then shape1.Left := shape1.Left+7;
  if (key = VK_LEFT)and(shape1.Left>=3) then shape1.Left:=shape1.Left-7;
end;
end.

---------------------
и уже TShape не будет убегать за границы формы! Но будет двигаться только влево и вправо...попробуйте сделать самостоятельно так чтобы TShape не выходил за границы формы сверху и снизу + самостоятельно разберите код...возникнут вопросы задавайте их в этой теме...
---------------------

itisiam 27.01.2007 21:58

Вопросы по уроку №3
 
Сначала хотелось бы сказать спасибо модератору за эту тему т.к. лично мне она очень помогает. =)
Теперь, собственно, к вопросам.()
1. Я не понял смысла этого кода, можешь объяснить?. У меня по оси x объект стал двигаться быстрее, а когда начинал выходить за пределы формы двигался с обычной скоростью. Не надо ли вставить что-то подобное ,чтобы он не мог выйти за пределы формы:
Код:

  if (Key=VK_RIGHT) and (Shape1.Left+Shape1.Width)>=Form1.ClientWidth
  then Shape1.Left:=Shape1.Left
  if (Key=VK_LEFT) and (Shape1.Left<0)
  then Shape1.Left:=Shape1.Left

Или же переписать основной код вот так:
Код:

  if (key=VK_UP) and (Shape1.Top>=0)
    then Shape1.Top:=Shape1.Top-2;
  if (key=VK_LEFT) and (Shape1.Left>=0)
    then Shape1.Left:=Shape1.Left-2;
  if (key=VK_DOWN) and (shape1.Top + shape1.Height <= Form1.ClientHeight)
    then Shape1.Top:=Shape1.Top+2;
  if (key=VK_RIGHT) and (shape1.Left + shape1.Width <= Form1.ClientWidth)
    then Shape1.Left:=Shape1.Left+2;

У меня это работает.

2. Можно по-подробнее о событии OnKeyDown ? В частности что за параметры передаются переменными Key, Shift?

zetrix 28.01.2007 08:39

Key - код клавиши, UNICOD вроде передаётся.
Shift - передаётся состояние клавишь Shift, Alt, Ctrl (нажаты или нет)

Нажми f1 (справка в делфе) и введи OnKeyDown,TWinControl там полностью описание есть + есть ссылка Virtual Key codes - там тоже много полезного.

psyke 28.01.2007 14:00

немного усложнив эту конструкцию становится интереснее ;)

Код:

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);

begin

 case Key of
 VK_LEFT:
 begin
 Image1.Picture.Bitmap.LoadFromFile('left.bmp');
 if image1.Left > 0 then
 image1.Left:=Image1.Left-image1.Width;
 end;

 VK_RIGHT:
  begin
 Image1.Picture.Bitmap.LoadFromFile('right.bmp');
 if image1.Left+image1.Width < ClientWidth then
 image1.Left:=Image1.Left+image1.Width;
 end;


 VK_UP:
  begin
 Image1.Picture.Bitmap.LoadFromFile('top.bmp');
 if image1.Top > 0 then
 image1.Top:=Image1.top-image1.Height;
 end;
 VK_DOWN:
  begin

    Image1.Picture.Bitmap.LoadFromFile('bottom.bmp');
          if not (image1.Top+Image1.Height > ClientHeight) then
    image1.top:=Image1.Top+image1.Height;

 end;

 VK_SPACE:
 begin
 paintbox1.Canvas.Rectangle(image1.Left+2,image1.top+2,
 image1.Left+image1.Width-1,image1.Top+image1.Height-1);
 end;



 VK_ESCAPE:
 begin
 Sendmessage(handle,WM_CLOSE,0,0);
 end;
 end;



  caption:='X: '+IntToStr(image1.Left div image1.Width)+' Y: '+
  IntToStr(image1.top div image1.Height);

end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
i: Integer;
cols,rows: Byte;
begin
if sender is ttimer then
paintbox1.Canvas.Create;

paintbox1.Canvas.Brush.Color:=clLime;
cols:=(panel1.Width div 50)+1;
rows:=(panel1.Height div 50)+1;
for i:=0 to cols do
begin
PaintBox1.Canvas.MoveTo((i mod cols)*50,0);
PaintBox1.Canvas.LineTo((i mod cols)*50,panel1.Height);

end;

for i:=0 to rows do
begin
PaintBox1.Canvas.MoveTo(0,(i mod rows)*50);
PaintBox1.Canvas.LineTo(panel1.Width,(i mod rows)*50);

end;
 timer1.Enabled:=false;
end;

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
case ord(key) of
  49: paintbox1.Canvas.Brush.Color:=clRed;
  50: paintbox1.Canvas.Brush.Color:=clBlack;
  51: paintbox1.Canvas.Brush.Color:=clYellow;
  52: paintbox1.Canvas.Brush.Color:=clLime;
  53: paintbox1.Canvas.Brush.Color:=clWhite;
  end;
end;

рисуем 4 имаги, пусть стрелочки, в разных направлениях, вверх, вниз, лево, право.. Х=50, Y=50 :)

таймер для избежания падения фокуса на какой-нить из контролов, потом стрелочка ваша ездить не будет.

в конечном итоге ваша стрелочка будет бегать по клеточному полю и принажатии на пробел будет закрашивать клеточки цветом. ах да! на форму кинуть панель а на неё paintbox не забудте и image -- ваша стрелочка!

зы-Shift это прежде всего множество из (ssShift, ssAlt, ssCtrl,
ssLeft, ssRight, ssMiddle, ssDouble), обращаться надо к ним через квадратные скобочки -- if shift = [ssShift] then ... if shift = [ssShift,ssAlt] then...
пробуй :)

Yogurt 25.02.2007 12:20

У меня назрел такой вопрос: при движении объекта с помощью клавиш появляется такой эффект, что, когда я зажимаю кнопку (например стрелочку), то объект сдвинется на n пикселов (где n это шаг, который задаётся заранее), затем остановится на, приблезительно, 0.5 с, а потом начинает нормально двигаться. Разумеется в игре такое движение неприемлемо, и хотелось бы знать как это устранить.

И второй вопрос заключается в том, что двигается объект слишком отрывисто (я предполагаю, что это из-за медленного действия компьютера, несмотря на то, что у меня очень мощная машина). Хотелось бы узнать, как сделать движение более плавным.

Speeker 26.02.2007 01:31

причина задержки скорее всего в настройках винды (есть иакой параметр - сколько времени держиться клавиша зажатой прежде чем применить к ней залипание) Выход я вижу в том что бы отключить опцию в настройках виндовс (скорее всего через реестр), а по выходу из игры снова включать. Или создать обработчик OnKeyDown, который приводит логическую переменную движения в соответствуующую сторону в True и OnKeyUp - все переменные движения в False, а движения обрабатывать в таймере.
А торможением возможно называешь мерцание объекта, если да попробуй использоватьпараметр
Form1.AlphaBlend:=True;

Cezar 02.03.2007 16:26

Цитата:

У меня назрел такой вопрос: при движении объекта с помощью клавиш появляется такой эффект, что, когда я зажимаю кнопку (например стрелочку), то объект сдвинется на n пикселов (где n это шаг, который задаётся заранее), затем остановится на, приблезительно, 0.5 с, а потом начинает нормально двигаться. Разумеется в игре такое движение неприемлемо, и хотелось бы знать как это устранить.
http://programmersforum.ru/showthread.php?t=982
Посмотри там последний пост, мож подойдет...

Yogurt 04.03.2007 08:46

Цитата:

Сообщение от Speeker (Сообщение 12304)
А торможением возможно называешь мерцание объекта, если да попробуй использоватьпараметр
Form1.AlphaBlend:=True;

Я попробовал вставить это в процедуру, но единственым изменением стало то, что форма 1 раз моргнула черным цветом и всё. Всё остальное осталось без изменений.

Далее назрел вопрос. Как сделать, чтобы можно было вставить в программу какой-то код (не в процедуры, которые находятся в модуле). Например, я сделал пятнашки и нужно, чтобы условие победы отслеживалось не при каком-то событии, а постоянно.:confused:

zetrix 04.03.2007 09:28

Цитата:

Например, я сделал пятнашки и нужно, чтобы условие победы отслеживалось не при каком-то событии, а постоянно
Хм... Я что-то не понимаю: как может наступить победа, если ничего не произошло? Ну в крайнем случае через таймер можно.

Yogurt 04.03.2007 11:07

У меня может быть огромное кол-во различных событий, которые приводят к победе, при этом в случае победы реализуется большой механизм. Это получается, что мне в каждую процедуру надо вствить один и тот же код? Даже если оформить это все в отдельную процедуру и вставлять только её название, но если событий более ста?

LepihinMS 13.03.2007 16:04

Значит перемудрил :)

execom 26.03.2007 13:06

Исходник Пятняшек!
 
Вложений: 1
2Yogurt:
Попробую, вам уважаемый помочь! Представив вам разсосанный сорец пятнашек! :) Назовём это урок №4 для начинающего!
Код:

{ Игра "15"}
unit game15_;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes,
  Graphics, Controls, Forms, Dialogs;
type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormPaint(Sender: TObject);
    // эти объявления вставлены сюда вручную
    procedure ShowPole;
    procedure Mixer;
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
const
    H = 4;  W = 4;  // размер поля - 4х4
    CH = 64; CW = 64; // размер клеток - 16х16
var
    // правильное расположение фишек
    stp : array[1..H, 1..W] of byte =
    (( 1, 2, 3, 4),
    ( 5, 6, 7, 8),
    ( 9,10,11,12),
    (13,14,15, 0));
    // игровое поле
    pole: array[1..H, 1..W] of byte;
    ex,ey: integer; // координаты пустой клетки
// новая игра
procedure NewGame;
var
    i,j: integer;
begin
    // исходное (правильное) положение
    for i:=0 to H+1 do
        for j:=0 to W+1 do
            pole[i,j] := stp[i,j];
    Form1.Mixer;    // перемешать фишки
    Form1.ShowPole; // отобразить поле
end;
// проверяет, расположены ли
// фишки в нужном порядке
function Finish: boolean;
var
    row,col: integer;
    i: integer;
begin
    row :=1; col :=1;
    Finish := True; // пусть фишки в нужном порядке
    for i:=1 to 15 do
    begin
      if pole[row,col] <> i then
      begin
            Finish:= False;
            break;
      end;
      // к следующей клетке
      if col < 4
          then inc(col)
      else begin
          col :=1;
          inc(row);
      end;
    end;
end;
 
// "перемещает" фишку в соседнюю пустую клетку,
// если она есть, конечно
procedure Move(cx,cy: integer);
// cx,cy - клетка, в которой игрок сделал щелчок
var
    r: integer;      // выбор игрока
begin
    // проверим, возможен ли обмен
    if not (( abs(cx-ex) = 1) and (cy-ey = 0) or
            ( abs(cy-ey) = 1) and (cx-ex = 0))
    then exit;
    // Обмен. Переместим фишку из x,y в ex,ey
    Pole[ey,ex] := Pole[cy,cx];
    Pole[cy,cx] := 0;
    ex:=cx;
    ey:=cy;
    // отрисовать поле
    Form1.ShowPole;
    if Finish then
    begin
        r := MessageDlg('Цель достигнута!'+ #13+
        'Еще раз?',mtInformation,[mbYes,mbNo],0);
        if r = mrNo then Form1.Close; // завершить работу программы
    end;
//end;
end;
// щелчок в клетке
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
    cx,cy: integer; // координаты клетки
begin
    // преобразуем координаты мыши в координаты клетки
    cx := Trunc(X / CW) + 1;
    cy := Trunc(Y / CH) + 1;
    Move(cx,cy);
end;
// выводит игровое поле
procedure TForm1.ShowPole;
var
    i,j: integer;
    x,y: integer; // x,y - координаты вывода
                  //  текста в клетке
begin
    // сетка: вертикальные линии
    for i:= 1 to W - 1 do
    begin
        Canvas.MoveTo(i*CW,0);
        Canvas.LineTo(i*CW,ClientHeight);
    end;
    // сетка: горизонтальные линии
    for i:= 1 to H - 1 do
    begin
        Canvas.MoveTo(0,i*CH);
        Canvas.LineTo(ClientWidth,i*CH);
    end;
    // содержимое клеток
    // x,y - координаты вывода текста
    for i:= 1 to H do
    begin
        y:=(i-1)*CH + 15;
        for j:=1 to W do
        begin
            x:= (j-1)*CW + 15;
            case Pole[i,j] of
            0:      Canvas.TextOut(x,y,'    ');
            1..9:  Canvas.TextOut(x,y,' '+IntToStr(Pole[i,j])+'  ');
            10..15: Canvas.TextOut(x,y,IntToStr(Pole[i,j]));
            end;
        end;
    end;
end;
// "перемешивает" фишки
procedure TForm1.Mixer;
var
    x1,y1: integer; // пустая клетка
    x2,y2: integer; // эту переместить в пустую
    d: integer;    // направление, относительно пустой
    i: integer;
begin
    x1:=4;
    y1:=4;
    randomize;
    for i:= 1 to 150 do
    begin
        repeat
            x2:=x1;
            y2:=y1;
            d:=random(4)+1;
            case d of
                1: dec(x2);
                2: inc(x2);
                3: dec(y2);
                4: inc(y2);
            end;
        until (x2>=1) and (x2<=4) and (y2>=1) and (y2<=4);
        // здесь определили фишку, которую
        // надо переместить в пустую клетку
        Pole[y1,x1] := Pole[y2,x2];
        Pole[y2,x2] := 0;
        x1:=x2;
        y1:=y2;
    end;
    // запомним координаты пустой клетки
    ex:= x1;
    ey:= y1;
end;
// обработка события OnCreate
procedure TForm1.FormCreate(Sender: TObject);
begin
    ClientWidth := CW * W;
    ClientHeight := CH * H;
    Canvas.Font.Name := 'Times New Roman';
    Canvas.Font.Size := 22;
    NewGame;
end;
// обработка события OnPaint
procedure TForm1.FormPaint(Sender: TObject);
begin
    Form1.ShowPole;
end;
end.


execom 27.03.2007 15:37

Вложений: 1
Урок № 5
Отдельный класс игрушек прадставлен, так называемыми игрушками на развитие памяти! Вот попробуем написать одну из таких! Что она будет делать!? А практически ни чего особенно сложно, просто запускаем прогу она на секунду показывает число, а потом число пропадает и появляется окно для ввода числа, там мы его по памяти вводим и если мы правильно ввели, то показывается следующее, а если неправильно, то следующее число будет показано после звукового сигнала об ошибке! Вот откоментированный исходник игры а ниже архив с исходником!
Код:

unit memory_;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;
type
  TForm1 = class(TForm)
    Label1: TLabel;
    Button1: TButton;
    Edit1: TEdit;
    Timer1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure Edit1KeyPress(Sender: TObject; var Key: Char);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
implementation
const
  KC = 5;  // разрядность числа (кол-во цифр)
  LT = 10;  // количество чисел (длинна теста)
var
  numb: integer;  // число, которое должен запомнить испытуемый
  right: integer; // количество правильно запомненных чисел
  n: integer;    // счетчик чисел
{$R *.dfm}
// генерирует k - разрядное число
function GetNumb(k: integer) : integer;
var
  n: integer; // генерируемое число
  i: integer;
begin
  // процедура генерирует число по разрядам
  // начиная со старшего
  n:= Random(9)+1; // старший разряд не может быть нулем
  // остальные разряды
  for i := 1 to (k-1) do
    n := n*10 + Random(10);
  GetNumb := n;
end;
// создание формы
procedure TForm1.FormCreate(Sender: TObject);
begin
  Edit1.Visible := False;  // скрыть поле ввода Edit1
  Edit1.MaxLength := KC;  // кол-во символов, которое можно ввести
  Label1.WordWrap := True; // разрешить перенос слов на следующую строку
  Label1.Caption :=
  'Сейчас на экране будут появляться числа. ' +
  'Вы должны запомнить число, набрать его на клавиатуре и нажать <Enter>';
  Button1.Caption := 'Начать';
  Timer1.Enabled := False;    // таймер остановлен
  Timer1.Interval := 1000;    // время показа числа - 1 секунда
  right := 0;    // кол-во правильных
  n := 0;    // счетчик чисел
  Randomize;    // инициализация ГСЧ
end;
// щелчок на кнопке "Начать/Завершить"
procedure TForm1.Button1Click(Sender: TObject);
begin
  if Button1.Caption = 'Завершить' then
    Form1.Close; // закрыть окно программы
  if Button1.Caption = 'Начать' then
  begin
      Button1.Caption := 'Завершить';
      Button1.Visible := False;  // скрыть кнопку
      // кнопка Button1 станет доступной после того
      // как испытание закончится
      Label1.Caption := '';
      Label1.Font.Size := 24;      // размер шрифта поля Label1
      Edit1.Font.Size := 24;        // размер шрифта поля Edit1
      // сгенерировать и вывести число
      numb := GetNumb(KC);
      Label1.Caption := IntToStr(numb);
      Timer1.Enabled := True;      // запуск таймера
      // процедура обработки сигнала от таймера
      // "сотрет" число
    end;
end;
// обработка события таймера
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Timer1.Enabled := False; // остановить таймер
  Label1.Visible := False; // скрыть число
  Edit1.Visible := True;  // сделать доступным поле Edit1
  Edit1.SetFocus;          // установить курсор в поле Edit1
end;
// нажатие клавиш в поле Edit1
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
var
  igrok: integer;  // число, которое ввел испытуемый
begin
    case Key of
        '0'..'9',#8:  ; // клавиши "0"-"9",<Backspace>
        #13:            // клавиша <Enter>
    begin
        igrok := StrToInt(Edit1.Text);
        if (igrok = numb)
          then right := right + 1;
        n := n + 1; // счетчик чисел
        Edit1.Text := '';
        Edit1.Visible := False;  // скрыть поле Edit1
        if n < LT then
        begin
          numb := GetNumb(KC); // сгенерировать следующее число
          Label1.Caption := IntToStr(numb); // отобразить число
          Label1.Visible := True;
          Timer1.Enabled := True;          // пуск таймера
        end
        else begin
          // испытание закончено
          // вывести результат
          Label1.Font.Size := 10;
          Label1.Caption := 'Результат:' + #13 +
            'Показано чисел:  ' + IntToStr(LT) + #13 +
            'Правильных:  ' + IntToStr(right);
          Label1.Visible := True;
          Button1.Visible := True;    // показывается кнопка "Завершить"
        end;
    end;
    else Key := Chr(0);
    end;
end;
end.


execom 29.03.2007 03:38

Вложений: 1
Урок №6!
Теперь попробуем написать игрушку развивающую реакцию! Суть её заключается в следующем, на экране появляются смайлики и на м нужно успавать по ним кликать курсором! В конце выдаётся результат о попаданиях и промахах!
Вот откоментированный исходник игры "Тир":
Код:

unit tir_;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;
type
  TForm1 = class(TForm)
    Timer: TTimer;
    Label1: TLabel;
    Button1: TButton;
    procedure TimerTimer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    { *****************************
      объявление процедур помещено сюда,
      чтобы процедуры имели прямой доступ
      к форме, на которой они рисуют
      ****************************** }
    procedure PaintFace(x,y: integer); // рисует рожицу
    procedure EraseFace(x,y: integer); // стирает рожицу
  end;
var
  Form1: TForm1;
  fx,fy: integer;  // координаты рожицы
  n: integer;      // количество щелчков кнопкой мыши
  p: integer;      // количество попаданий
implementation
// рисует рожицу
procedure TForm1.PaintFace(x,y: integer);
begin
    Canvas.Pen.Color := clBlack;    // цвет линий
    Canvas.Brush.Color := clYellow;  // цвет закраски
    // рисуем рожицу
    Canvas.Ellipse(x,y,x+30,Y+30);      // лицо
    Canvas.Ellipse(x+9,y+10,x+11,y+13);  // левый глаз
    Canvas.Ellipse(x+19,y+10,x+21,y+13); // правый глаз
    Canvas.Arc(x+4,y+4,x+26,y+26,x,y+20,x+30,y+20); // улыбка
end;
// стирает рожицу
procedure TForm1.EraseFace(x,y: integer);
begin
  // зададим цвет границы и цвет закраски,
  // совпадающий с цветом формы. По умолчанию
  // цвет формы - clBtnFace (см. в Object Inspector)
  Canvas.Pen.Color := clBtnFace;  // цвет окружности
  Canvas.Brush.Color := clBtnFace; // цвет закраски
  Canvas.Ellipse(x,y,x+30,y+30);
end;
 
{$R *.dfm}
procedure TForm1.TimerTimer(Sender: TObject);
begin
    EraseFace(fx,fy);
    // новое положение рожицы
    fx:= Random(ClientWidth-30);  // 30 - это диаметр рожицы
    fy:= Random(ClientHeight-30);
    PaintFace(fx,fy);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
    // исходное положение рожицы
    fx:=100;
    fy:=100;
    Randomize;  // инициализация генератора
                // случайных чисел
end;
// нажатие клавиши мыши
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  inc(n);  // кол-во щелчков
  if (x > fx) and (x < fx+30) and
    (y > fy) and (y < fy+30)
  then begin
      // щелчок по рожице
      inc(p);
      end;
  if n = 10 then
    begin
        // игра закончена
        Timer.Enabled := False; // остановить таймер
        ShowMessage('Выстрелов: 10. Попаданий: ' +
                IntToStr(p)+'.');
        EraseFace(fx,fy);
        Label1.Visible := True;
        Button1.Visible := True;
        // теперь кнопка и сообщение снова видны
    end;
end;
// щелчок на кнопке Ok
procedure TForm1.Button1Click(Sender: TObject);
begin
    Label1.Visible := False;  // скрыть сообщение
    Button1.Visible := False; // скрыть кнопку
    Timer.Enabled := True;    // пуск таймера
end;
end.

А это полностью исходник игры!

execom 30.03.2007 09:02

Морской бой
 
Вложений: 1
Урок №7
Практчески любой и каждый уважающий себя человек в своей жизни хотя бы раз играл в эту занимательную стратегическую игрушку - Морской бой! Исходник не такой простой, как в предыдущих примерах, но и не сложный, разобраться при желании можно! При желании вы можете дороботать игру добавив новые стили игры (их существует огромное множество)! Можно доработать стратегию компа! А можно просто оптимизировать (а скорей адаптировать) интерфейс под себя!
Игра в принципе работает, но компьютер довольно просто рвёт!... :)

execom 01.04.2007 23:22

Вложений: 3
Урок №8
Немного теории по особенностям создания игр разных жанров!
Anim_Games.rar - Анимация в компьютерных играх;
Arcade_Games.rar - Аркадные игры;
Prikluch_Games.rar - Приключеньческие игры.

execom 03.04.2007 20:18

Вложений: 1
Урок №9
А вот исходник более серьёзной и весьма увлекательной игрухи! Игра называется "Линии"! Цель игры методом передвиженя кружков необходимо поставить в ряд 4 и более кружка одного цвета, при этом они исчезают! При каждом ходе появляется несколько новых кружков. Игра заканчивается когда заканчивается место на игровом поле! Что бы передвинуть кружок, надо по нему щёлкнуть, а потом щёлкнуть по месту назначения, но при том условии что кружок сможет доехать до места назначения не перепрыгивая (хотя можно обходить) через другие кружки! В общем кому интересно разберитесь с исходником, он там не сложный, а кому не очень это интересно, советую поиграть!!! :)

execom 05.04.2007 00:33

Вложений: 1
Урок №10
Вот пример того как можно работать с возможностями 3D в Delphi!
Простенький мануальнчик с примером исходника!

Alar 05.04.2007 11:50

Цитата:

Сообщение от execom (Сообщение 15528)
Урок №10
Вот пример того как можно работать с возможностями 3D в Delphi!
Простенький мануальнчик с примером исходника!

Заинтересовало, а готовых исходников нет?

execom 09.04.2007 22:30

Вложений: 1
Урок №11
Вот исходник программы работы с 3D объектом, его можно вращать, и изменять его размер!

execom 12.04.2007 07:54

Урок №12
Что такое OpenGL?
В этом уроке мы поговорим о том, что вообще такое OpenGL, для чего это нужно. Для начала, вы должны неплохо знать ОС Windows, а также язык Си++ (в данном случае, Visual C++, так как мы будем работать именно в этой среде разработки).
Итак, OpenGL (Открытая Графическая Библиотека) - это программный интерфейс (API) для разработки приложений с использованием 2D и 3D графики.
OpenGL стоит как бы между аппаратным обеспечением, и пользовательским уровнем.
Основные особенности этой библиотеки являються:
Стабильность:
Это означает, что дополнение в OpenGL реализуется так, что бы сохранить совместимость с более старым программным обеспечением.

Переносимость (независимость):
Код программы, которую вы написали, скажем, под Windows, можно легко перенести на Linux и другие ОС. То есть, OpenGL не зависит от какой ни будь операционной системы, как, например DirectX.
Простота в использовании:
Приложения, написанные с помощью OpenGL, имеют сравнительно небольшой объем кода. Также эта библиотека имеет понятный интерфейс. И разобраться в коде программы очень просто.
Ну и наконец OpenGL это отраслевой стандарт, т.е. вы можете взять исходники и сделать на их юызе что-нибудь своё.
Основные возможности OpenGL:
· Набор базовых примитивов: точки, линии, многоугольники и т.п.
· Видовые и координатные преобразования
· Удаление невидимых линий и поверхностей (z-буфер)
· Использование сплайнов для построения линий и поверхностей
· Наложение текстуры и применение освещения
· Добавление специальных эффектов: тумана, изменение прозрачности, смешивание цветов (blending), устранение ступенчатости (anti-aliasing). Я думаю, что всех этих достоинств достаточно для того, чтобы выбрать OpenGL для создания 3D графики (игр, в частности).

execom 12.04.2007 07:57

Урок №13

Основные термины и понятия компьютерной графики.

Рендеринг- это процесс подготовки, выдачи (прорисовки) изображения на экран. В общем, это все действия, которые связаны с выдачей картинки на экран.
Буфер- это область для временного хранения данных.
Двойная буферизация- это один из способов рендеринга, при котором существует два буфера. Содержимое первого (переднего) буфера (front buffer) показываеться на экран и вы видите какое то изображение. В это время на заднем буфере (back buffer) подготавливается следующий кадр (рисуется). Когда кадр на заднем буфере готов, тогда передний и задний буфер меняются местами. И затем все это повторяется. С помощью такой технологии избегается мерцание экрана.
Пиксель- это наименьшая точка, которую можно различить на экране. Он является единицей двухмерного изображения.
Камера- это не то, что вы подумали… :) Камера- это место, из которого вы смотрите на экран.
Трансформация- нахождение координат точки в заданной системе координат, используя координаты точки в другой системе (это переносы, или вращения). При трансформации положение точки не меняется.
Мировая система координат- это система координат, которая считается неподвижной. Обычно относительно этой системы координат задаются положение камеры, и объектов.
Примитив- это основная единица, из которой строятся сложные объекты. Примитивом может быть: точка, линия, треугольник, или что ни будь подобное…
Z-buffer- также часто вместо этого слова употребляется слово Буфер Глубины (Depth Buffer). Это буфер величиной с экран, в котором хранятся Z координаты пикселей. Z-ось добавляет третью величину- глубину.
Матрица- в компьютерной графике, это массив чисел (обычно 4х4), который содержит значения векторов систем координат.
Проекция- это перевод координат из пространства (камеры) на экран, или с 3х мерных координат в 2х мерные.

execom 18.04.2007 08:11

Вложений: 1
Урок 15
Интересный пример по проецированию курсора мыши на 3-х мерную поверхность! Данный пример будет интересен как новичкам, так и профессионалам.

execom 24.04.2007 06:53

Вложений: 1
Урок №16
Данный исходник программы для игры в Русские шашки! Причем соперник имеет достаточно высокий интелект! :)

Dura4ok 07.05.2007 14:02

Что за нах???
 
Я пытаюсь сделать арканоид, уже прописал физику мяча, но не могу теперь описать движение платформы.
записал всё как в вашем первом уроке в том же юните, и ничего не происходит.
З.Ы: в чистом юните всё работает.
Памагити!!!
Цитата:

unit Horray;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, Buttons, XPStyleActnCtrls, ActnList, ActnMan;
type
TForm1 = class(TForm)
Shape1: TShape;
Shape2: TShape;
ZGMI: TButton;
procedure ZGMIClick(Sender: TObject);
private
public
procedure HandleMessages(var Msg: tMsg; var Handled: Boolean);
procedure FormCreate(Sender: TObject);
end;
var
Form1: TForm1;
implementation

{$R *.dfm}


procedure TForm1.ZGMIClick(Sender: TObject);
begin
while (Shape1.Left + Shape1.Width < Form1.Width) and (shape1.Top > 5) do
begin
shape1.Top := shape1.top -5;
Shape1.Left:= Shape1.Left + 5;
Sleep(10);
Form1.Refresh;
end;
if Shape1.Left + Shape1.Width < Form1.Width then
while Shape1.Left + Shape1.Width < Form1.Width do
begin
shape1.Top := shape1.top +5;
Shape1.Left:= Shape1.Left + 5;
Sleep(10);
Form1.Refresh;
end
else
while shape1.Top > 5 do
begin
shape1.Top := shape1.top -5;
Shape1.Left:= Shape1.Left -5;
Sleep(10);
Form1.Refresh;
end;
if Shape1.Left + Shape1.Width = Form1.Width then
while shape1.top< form1.height - shape1.height do
begin
shape1.Top := shape1.top +5;
Shape1.Left:= Shape1.Left -5;
Sleep(10);
Form1.Refresh;
end
else
while (shape1.top< form1.height - shape1.height) and (Shape1.Left > 0) do
begin
shape1.Top := shape1.top +5;
Shape1.Left:= Shape1.Left -5;
Sleep(10);
Form1.Refresh;
end;
while shape1.top< form1.height - shape1.height do
begin
shape1.Top := shape1.top +5;
Shape1.Left:= Shape1.Left +5;
Sleep(10);
Form1.Refresh;
end;
end;
procedure tForm1.HandleMessages(var Msg: tMsg; var Handled: Boolean);
begin
if (Msg.Message = WM_KeyDown) and
(Msg.wParam in [VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT]) then
begin
case Msg.wParam of
VK_UP: ShowMessage;
VK_DOWN: ShowMessage;
VK_LEFT: ShowMessage;
VK_RIGHT: ShowMessage;
end;
Handled := True;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnMessage := HandleMessages;
end;
end.

НЕ_АЙС 07.05.2007 15:29

Вложений: 1
Остальное сам допишешь

Dura4ok 07.05.2007 15:31

ПАСИИИИБ!!!!!!!!!!!!!

Dura4ok 08.05.2007 08:57

ну а
 
ну а с моей то что?

Horny 20.09.2007 12:45

люди, да что с вами, при всём желании у вас не получится создать более или менее нормальную игру используя VCL, идеальный вариат - это DirectDraw, но для некоторых он может показаться сложным, для 2D игр есть альтернатива, для начала учите WinApi, затем создаете форму сами(то есть пишете всё ручками) при этом у вас не будет ненужных бордеров и в полноэкранном режипе панель задач не будет вам мешать, затем создаёте переменные в которые вы будете грузить картинки, и пользуемся функцией BitBlt() для копирования фрагментов изображений, при этом у вас не будет ни остановок ни мерцания (если вы создаёте "оконную" игру форму сами можете не писать, но вот размер вашего приложения будет о-го-го какой)

Kostia 25.11.2007 15:56

Horny, я с вами полностью согласен насчет создания игр с помощью средств DX, но для начинающих игроделов очень тяжело сразу взять и начать писать своё детище на DX, я веду к тому, что следует начинать с простого и постепенно двигаться к большему.

Beermonza 25.11.2007 16:13

Тоже согласен с комрадом Kostia, ...начинается все с элементарного Image, затем переход на Canvas (буферизация, вставка Bitmap), затем Win API (GDI), а уже к концу DirectX, вершина - ассемблер. Почему так? , ...потому, что нужно пройти весь путь, только тогда можно понять принципы и выбрать методы для решения конкретной задачи. Иногда можно обойтись и приметивными методами, если они удовлетворяют условию.

mutabor 25.11.2007 16:22

А где же OpenGL? Ей нет места в вашей иерархии? :)

Да, и мне кажется не стоит путать понятия создание игр и создание графических библиотек.

Какое имеет отношение ассемблер к созданию игр???

Beermonza 25.11.2007 17:10

Цитата:

Сообщение от mutabor (Сообщение 51483)
А где же OpenGL? Ей нет места в вашей иерархии? :)

Иерархии небыло, просто пример продвижения. Эт как захочется, но основные части показаны ИМХО.

Цитата:

Сообщение от mutabor (Сообщение 51483)
Какое имеет отношение ассемблер к созданию игр???

Самое прямое, там где нужна скорость, там и ассемблер, отрицать глупо :)

Pfent 03.12.2007 07:46

Подскажите плз как сделать так, чтобы при нажатии на форму персонаж шел туда куда было нажато))???

Speeker 03.12.2007 12:53

Есть событие OnMouseUp в нем переменные х и у в которые передаются координаты мыши. Соответственно туда и перемещаеш своего персонажа...

Pfent 03.12.2007 15:24

Спс нада будет попробывать :):):)

Simply-Art 03.12.2007 15:39

Подскажите как обрабатывать сразу несколько клавишь, вот например в аркаде, надо одновременно жать W и D (вперёд и вправо). Как это реализовать?

Pfent 03.12.2007 15:43

Цитата:

Сообщение от Speeker (Сообщение 53557)
Есть событие OnMouseUp в нем переменные х и у в которые передаются координаты мыши. Соответственно туда и перемещаеш своего персонажа...

Спс помогло!:) Но у меня еще вопрос) Как сделать что бы обьект плавно шел к точке в которую нажал?? просто может я неправильно написал:

if button = mbleft
then
shape1.Left:=x;
shape1.Top:=y;
или нужно воспользоваться таймером?
если да то как?:confused: :confused: :confused:

Kostia 03.12.2007 16:42

Цитата:

Сообщение от Simply-Art (Сообщение 53599)
Подскажите как обрабатывать сразу несколько клавишь, вот например в аркаде, надо одновременно жать W и D (вперёд и вправо). Как это реализовать?

Код:

var
  Key: tkeyboardstate;
  i: integer;
begin
  form1.Caption:='';
  windows.GetKeyboardState(key);
  for i:=0 to 255 do
    if (key[i]=128)or(key[i]=129)then
      form1.Caption:=form1.Caption+' '+inttostr(i);
end;

Попробуй в таймере.

Beermonza 03.12.2007 21:28

Вложений: 1
Pfent, вот примерчик. Все грубо, установи смещение на картинку и будет идти туда куда ткнул мышью.

Pfent 04.12.2007 09:39

Огромное спасибо за пример :):):)

Speeker 05.12.2007 14:35

Пользоваться таймером. там прописать что то типа если координата х больше левфт то лефт=лефт+1.... то же самое с у, кроме того может быть такое что добавлять надо не единицу... можно попробовать реализовать это через уравнение прямой...

mutabor 07.12.2007 00:30

Вот вам в качестве урока по созданию логических игр (это не РПГ =).
Исходник игры кликомания (коллапс) на Дельфи.
http://www.programmersforum.ru/attac...4&d=1196863119

BBagi 26.12.2007 08:55

Всем приветик=) Помогите произошел клинический ступор=) Гляньте свежим взглядом....=) Cуть задачи такова: кнопка при нажатии двигается вправо до ходя до края формы а после ползет в лево.

Procedure TForm1. для нажатия...
begin
if Button1.Left>600 then Button1.left:=Button1.left-5 else
if Button1.left<600 then Button1.left:=Button1.left+5 else
Button1.left:=Button1.left+5
end; end.

Сама вижу что даю условие до 600 она доползает и начинает дергаться то +5 то _5. Тут как-то может нужно вести переменную и менять ей знак?

Speeker 27.12.2007 17:32

Просто введи переменную булевского типа заначение фалз, если достигнут предел движени вправо изменить на тру если значение тру двигать влево при достижени крайнего левого пложение опять изминить значение на фалз...

mutabor 01.01.2008 18:47

Еще можешь сделать переменную Speed: integer; определяющую скорость, т.е. на сколько пикселей за раз перемещается кнопка.
При достижении стенок меняешь знак скорости +/-
if (Button1.Left>600)or(Button1.left<0 ) then Speed:=0-Speed;
Потом в любом случае прибавляешь эту скорость
Button1.left:=Button1.left+Speed;

Лубышев 04.02.2008 20:44

Тут уже рассматривался пример движения оъекта при нажатии на кнопки с клавиатуры, а если одновременно нажаты влево и вверх?
или пользователь пользуется "перекатом"(не отпуская жмет на другую кнопку. а потом первую отпускает)

Лубышев 04.02.2008 21:17

Еще один вопрос.Как клонировать обьект
Допустим стратегия. Нужно построить дом. Допустим это Image.
Как сделать так чтоб создавался image в определенной области формы (любое количество, сколько вздумается пользователю) с соответствующим изображением здания
И к этому image относились бы все процедуры заранее оговоренные для данного типа сооружения
Например при двойном нажатии активировлась какая-то панель или что-то вроде этого.

zetrix 04.02.2008 21:23

Лучше создавать собственный класс...
Можно компонент. Разницы в принципе нет.

Лубышев 04.02.2008 21:46

А по подробнее...

Beermonza 05.02.2008 15:43

Поворот
 
Стоп, стоп, стоп!
Лубышев, про клоны Image забудьте раз и на всегда. Пример был дан для демонстрации, применим в аркаде, квесте, может в РПГ от части, все в любительском режиме, но никак не для стратегий.
Вообще, сначала стоит подумать о ресурсоемкости игры, если проба своих сил можете попробовать клон, но не советую. В основе простейшей 2D игры - один объект отображения графики. Начните с того, что создайте Image, назовите его Screen, растяните на размер формы или как угодно, и с помошью Canvas можете делать клоны чего-угодно куда-угодно в эиот Screen. Почему Canvas?

1. Топик говорит сам за себя, проще канвы нет ничего.
2. Для стратегии Canvas подойдет в виду статичности объектов.

Заинтересовались? спрашивайте...

mutabor 05.02.2008 17:23

Цитата:

Сообщение от Лубышев (Сообщение 72335)
Тут уже рассматривался пример движения оъекта при нажатии на кнопки с клавиатуры, а если одновременно нажаты влево и вверх?
или пользователь пользуется "перекатом"(не отпуская жмет на другую кнопку. а потом первую отпускает)

Создаешь четыре переменные типа boolean, на каждую клавишу по одной.
Назови их например LeftPressed, UpPressed ну и дальше в таком роде. Это будут флаги обозначающие нажата данная клавиша или нет.
При запуске они изначально все будут false (как и все глобальные boolean если их не инициализировать). Нам это подходит, так что пока их не трогаем.
Теперь пишем обработчики событий нажатия клавиши и отпускания. OnKeyDown и OnKeyUp.
Код:

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
// 37 - 40 это коды стрелок
if key = 37 then LeftPressed:=true;
if key = 38 then UpPressed:=true;
if key = 39 then RightPressed :=true;
if key = 40 then DownPressed :=true;
end;

procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
if key = 37 then LeftPressed:=false;
if key = 38 then UpPressed:=false;
if key = 39 then RightPressed :=false;
if key = 40 then DownPressed :=false;
end;

В принципе это все. Теперь где тебе нужно проверяешь состояние флагов.

Лубышев 10.02.2008 19:48

mutabor спасибо! Я так думаю уроки и надо было с этого начинать. Чтож за такая игра, когда нельзя одновременно нажать на две кнопки.

Что-то тело как то непонятно движеться, что-то не то я делаю. а есть готовый рабочий пример?

Beermonza, не могли бы вы расказать более подробно об том, что вы говорили? могли бы вы дать маленький примерчик, чтобы я все понял.

Beermonza 11.02.2008 16:52

Подробно
 
Начните с главного.

- Стратегия - это игра с действиями на карте;
- Карта - это клетки с объектами на них;
- Информационный скелет карты - двумерный массив.

Начинайте создавать игру со "скелета" карты (анализ ПО, сбор данных, типизация, ТЗ и пр. предшествующие пункты плана создания игры вы уже должны были проделать). Тип массива может быть выбран совершенно любым, ...вы должны обдумать каким образом можно представить данные, отвечающие за тот или иной объект.
Допустим, вы решили представлять некоторый объект (например, дом) числом, то массив у вас будет Word типа, поскольку видов объектов в стратегиях большое множество. Но, вам совершенно не удобно использовать такой код. Попробуете сделать таблицу на все 65536 значений, где за каждым числом закреплен рисунок? ...врятли!, ...да и тип Byte, вам тоже не подходит. Что же делать?
Давайте вспомним, что каждая ячейка массива может быть не только вместилищем одного типа данных, но и массивом записей или объектов, которые мы можем сами прописать, и указать нужный их тип. Вот так можно представить упрощенный массив объектов, для простой демонстрации:

Код:

Type
  TGameObject = object
    TGOBitmap:    TBitmap; // картинка объекта
    TGOName:      String;  // название объекта в игре
    TGODispX:    Word;    // смещение картинки по-X
    TGODispY:    Word;    // смещение картинки по-Y
  end;

Теперь мы будем использовать этот тип для двумерного массива (ограничим карту 100х100):

Код:

Var
  GameMapMas: array[0..100, 0..100] of TGameObject

Заполняется этот массив в начале игры (загрузка карты), ...затем по мере строительства объектов в самой игре, т.е. тут вы должны четко себе представлять как все происходит в стратегиях, создать процедуры на все случаи изменения карты. Это происходит простым заполнением подмассива в массиве карты:

Код:

GameMapMas[j,i].TGOBitmap:={указатель на картинку, массив текстур};
GameMapMas[j,i].TGOName:={указатель на имя объекта, массив текстур};
GameMapMas[j,i].TGODispX:={указатель на смещение картинки, массив текстур};
GameMapMas[j,i].TGODispY:={указатель на смещение картинки, массив текстур};

i,j -это координаты объекта на карте. Массив текстур уже одномерный, но также содержит в каждой ячейке множество объектов. Тут следует подумать, какие сопутствующие данные, кроме текстуры, вам понадобятся, ...это и тип, подтип, имя, смещение, состояние (вариант текстуры для разных состояний объекта в игре: дом целый, дом сломанный.)

Отображение объектов игры через Canvas

Как применить Canvac вы уже наверное знаете, но тем не мение, уточню. У нас есть экран игры Screen - это объект Image, есть скелет карты - массив GameMapMas, нужно их совместить вот такой строкой:

Код:

Screen.Canvas.Draw((j*MX)-GameMapMas[j,i].TGODispX, 
                            (i*MY)-GameMapMas[j,i].TGODispY,
                            GameMapMas[j,i].TGOBitmap);

MX, MY - это масштаб карты по-X и по-Y в пикселах. Применять эту строку можно в цикле, например, когда идет загрузка карты, или дискретно, на координаты мыши, где следует отобразить объект.

Это только одна сторона медали, также серьезно следует взяться за задний план карты - это поверхность, как ее нужно отображать, и что она из себя представляет? ...может это просто фон одного цвета, а может и мозаика из разных кусочков - тип грунта и пр. Прежде чем что-то рисовать канвой, следует вернуть назад участок заднего плана, как это будет происходит, зависит от вашего выбора.

mutabor 11.02.2008 23:19

Цитата:

Попробуете сделать таблицу на все 65536 значений, где за каждым числом закреплен рисунок? ...врятли!
А зачем таблица? Вот способ если кроме рисунка ничего хранить не надо:

array of array of word + TImageList

TImageList.Draw(canvas,x,y,map[mapx,mapy]);

Beermonza 12.02.2008 15:11

Цитата:

Сообщение от mutabor (Сообщение 74556)
А зачем таблица? Вот способ если кроме рисунка ничего хранить не надо:

array of array of word + TImageList

TImageList.Draw(canvas,x,y,map[mapx,mapy]);

Про таблицу - это сарказм, ...любой способ имеет право на жизнь.

Для начала можно попробовать и просто картинку, ...только это будет графический редактор, или что-то в роде одноразовой аппликации. Все равно придется думать над хранением других данных, кроме картинки, и при том с как можно простым алгоритмом параллельного использования.

Советую отказаться от использования объектов, если в них нет нужды, ...ведь нам нужен сам факт хранения картинок в ОЗУ, давайте делать это напрямую в массив, и выводить рисунок из памяти сразу в объект отображения без посредников. Обратите внимание на то, что в цикле прорисовки кадров в скором времени, когда игра будет совершенствоваться, появится множество процедур, ...тут идет борьба за каждую команду, за правильность выполнения последовательности, ...мы должны будем даже отказаться от привычного умножения (*) и деления (/), заменив их сдвигами.

mutabor 12.02.2008 23:32

Цитата:

Сообщение от Beermonza (Сообщение 74704)
...тут идет борьба за каждую команду, за правильность выполнения последовательности, ...мы должны будем даже отказаться от привычного умножения (*) и деления (/), заменив их сдвигами.

когда все становится настолько серьезно, пора вспоминать о двух графических библиотеках, мы все знаем как они называются ;)
конечно, если не делать сдвиги ради самих сдвигов :)

p.s. TImageList выводит графику довольно быстро, для учебных целей хватит с головой, а по своей сути он оболочка к системному имиджлисту.
Свои объекты работают не намного быстрее стандартных, вообще ООП это тормоз, от него тоже нужно отказываться если нужна сверхскорость.

Beermonza 14.02.2008 17:33

Не буду спорить, ...начинающие выберут метод по легче, если он их устраивает. Давайте не будем ссылаться на две библиотеки :), ...и без них можно обходиться и довольно быстро все отрисовывать.

Лубышев 17.02.2008 19:39

у меня все еще сохранилась проблема при нажатии на две кнопки одновременно... что делать?

Alar 17.02.2008 20:47

Ответ прост использовать флаги в памяти. если нажата кнопка вверх один флаг становиться true, если нажата кнопка влево, проверяем все флаги и если верхний флаг true выполняем другое действие.

Лубышев 17.02.2008 21:46

мне это уже обьясняли, но видемо, что-то не так делаю. Дайте готовый пример.

Beermonza 18.02.2008 17:22

Пример мультиопроса клавиатуры
 
Вложений: 1
Лубышев, вот этот самый пример, как и ранее описанный. Мы меняем значения флагов (переменные типа Boolean), в зависимости от нажатия клавиш, это прописывается в OnKeyDown и OnKeyUp фомы. Флаги после этого можно использовать как угодно, я создал процедуру, где изменяю цвет букв нарисованных клавиш.

Kostia 19.02.2008 18:07

Я бы написал функцию которая проверяла нажата клавиша с номером key или нет:
Код:

function keypressed(key: byte): boolean;
var
  keys: TKeyboardState;
begin
  result:=false;
  GetKeyboardState(keys);
  if(keys[key]=128)or(keys[key]=129)then result:=true;
end;

39- left
37- right
40- down
38- up
13-enter
27-esc
...
Например
if keypressed(27) then form1.close;

mutabor 09.04.2008 17:26

Делаем Пазл
 
Вложений: 1
Один из вариантов как можно сделать игру пазл.
Исходник с комментариями, читайте там.
Версия 0.1 (работает еще не все)
В следующей доделаю, а еще в следующей глянец наведу.

AngelOfDeath 30.04.2008 13:56

А есть какая нить литература по созданию игр на Delphi?

mutabor 30.04.2008 15:12

Цитата:

Сообщение от AngelOfDeath (Сообщение 96397)
А есть какая нить литература по созданию игр на Delphi?

Написание игр на Дельфи ничем особо не отличается от написания игр на другом языке.

Вопрос на засыпку: Где можно достать рецепт приготовления борща в эмалированной кастрюле?

Может отличаться реализация графики: GDI, OpenGL, DirectX. Если использовать борландовскую VCL, то это будет GDI графика, но это не обязательлно может быть только Дельфи, C++ Билдер также использует VCL.

Короче говоря проще найти отдельно литературу по игровым алгоритмам, нужному языку и графической библиотеке.

[Smarik] 30.04.2008 15:49

Здравствуйте, у меня вопрос насчет 2D движков для делфи, кто нить что то подобное встречал? Еще интересно что именно должен содержать движок и в каком виде все это представлено? Предположим я знаю как создать систему боя, магазины и большинство основных элементов в игре, но делать из этого игру не хочется, т.к. например продолжение придется писать с нуля, легче написать движок подгрузив в него графику, сюжет...понимаю что это гараздо сложнее, но если понять принцип, возможно что то получится.

mutabor 30.04.2008 18:23

Цитата:

кто нить что то подобное встречал?
HGE, Omega, eXgine, pHEngine, DGLEngine, YOK и другие, ну и конечно же DelphiX. Если хорошо знать OpenGL или DirectX, можно на них "чистых" делать или свой движок для себя написать.
Цитата:

Еще интересно что именно должен содержать движок
Что автор включит то и будет содержать, как минимум инициализацию, загрузку текстур. Ну и конечно всякие графические навороты, спрайты, частицы.
Цитата:

в каком виде все это представлено?
DLL, бывает Дельфи компонент + DLL

Дальше не совсем понял. Графический 2D движок это одно, а конструктор игр это другое. А свой собственный игровой движок-заготовка, в к-ром пол игры уже написано, это третье.

Kostia 05.05.2008 09:11

Урок xxx
Самая главная ошибка первых Русских разработчик, это то что они не убирали за собой мусор, что приводило к понижению производительности игры и к ее зависанию. Не поленитесь очистить память от мусора. Память нужно чистить после завершения уровня, при переходе в другую локацию и при завершении программы.

Простой пример
Bitmap.free;
Bitmap:=nil;

RealSHELS 19.05.2008 19:51

А что разве когда програма закрывается то оно все само не уничтожается?
Все компоненты находятся на форме, нет формы, нет компонентов, зачем чистить.

Beermonza 19.05.2008 21:31

Вам рано или поздно придется работать с переменными, хранящими в себе большие области данных, например TBitmap, после завершения работы программа удалит переменную, но не данные в ОЗУ, на которые она ссылается.

mutabor 20.05.2008 15:58

А помоему Delphi за собой убирает. Это если самому память выделять, то тогда самому и чистить, а если средствами Delphi то она сама освободит. Освобождение памяти после себя это одно из достоинств Delphi (и некоторых других языков) и один из недостатков например C++.
Вобщем от языка зависит и от того как память выделяется.

Beermonza 20.05.2008 17:51

Цитата:

Сообщение от mutabor (Сообщение 103231)
А помоему Delphi за собой убирает. Это если самому память выделять, то тогда самому и чистить, а если средствами Delphi то она сама освободит. Освобождение памяти после себя это одно из достоинств Delphi (и некоторых других языков) и один из недостатков например C++.
Вобщем от языка зависит и от того как память выделяется.

Именно так, ...стандартные вызовы и создание переменных, без вмешательства пользователя в сакральные их алгоритмы после завершения за собой Delphi чистит, ...но мы уже раскрыли достаточно секретов повышения скорости вывода графики ). Постепенно в программе начинающего игростроителя перемешаются стандартные методы и "ручные", среди всего множества легко запутаться и не "убрать за собой" в нужных случаях. Kostia призывает исключить случайное "замусоривание" памяти, которое действительно может привести к падению программы (или более серьезным последствиям), путем принудительного ее очищения, даже если это может и не требуется. Все должно быть освобождено! ...это правило номер 1 и у меня, что касается графики.

Kostia 21.05.2008 13:28

Когда я делал Аканоида, я не освобождал устройство и после запусков 15-20 игры, вся виндозовская GDI полетела: на рабочем столе иконки не отображались, в папках вместо иконок муть разная была, не отображались элементы пуска и т.д. А не освобождение поверхностей с картинками вызывало тормоза в игре и др. играх и решить эту проблему можно было только перезагрузкой компьютера.
Теперь освобождение ресурсов у меня на первом месте.

doctor_dre 24.05.2008 21:03

Друзя помогите..........
 
:confused: :confused: :confused: Нужна помощ в созд прогр "Сквош"
дана задача :
написать Игру: на игровом поле есть панель, что управляется мышей или клавиатурой. Шарик перемещается по полю отталк от стенок и панели. Задача игрока отбить шарик мах количество раз.
Требования:
Нужны функцииї:
1) подсчет баллов;
2) подсчет количества попыток;
3) сохранение результата таблица результатов;

:confused: .... плизззззззззз..........

mutabor 24.05.2008 21:27

С такими просьбами во фриланс.

anton14 25.05.2008 18:31

Подскажите,пожалуйста, как мне реализовать постоянное движение обьекта через Timer1. Допустим пользователь ввел с клавиатуры "up"
обьект непрерывно двигается вверх, соответственно "down" вниз и тд.

Beermonza 25.05.2008 20:08

Цитата:

Сообщение от anton14 (Сообщение 105554)
Подскажите,пожалуйста, как мне реализовать постоянное движение обьекта через Timer1. Допустим пользователь ввел с клавиатуры "up"
обьект непрерывно двигается вверх, соответственно "down" вниз и тд.

Создайте переменные типа Boolean. На OnKeyDown придавайте одной из переменных True остальным - False. В таймере напишите условия, если переменные принимают True, то выполняйте смещение в нужном направлении на заданное число.

mutabor 25.05.2008 20:32

Цитата:

Сообщение от anton14 (Сообщение 105554)
Подскажите,пожалуйста, как мне реализовать постоянное движение обьекта через Timer1. Допустим пользователь ввел с клавиатуры "up"
обьект непрерывно двигается вверх, соответственно "down" вниз и тд.

Вернись в этой же теме на несколько страниц назад, вот сюда, и читай начиная оттуда.

Beermonza 25.05.2008 22:35

anton14 может будут уточнения к вопросу? Если ищется алгоритм перемещения типа Пакмэна, то OnKeyUp уже применять не нужно, а OnKeyDown несколько модифицируется. Именно это прослеживается в вопросе.

L_M 03.06.2008 22:45

я еще не делал игр с движением, поэтому не знаю: стоит ли выводить на канву формы? или сразу надо учить, например опенгль. при рисовании по канве возникает мерцание... В общем что перспективнее: простота канвы или красота более профессиональных библиотек. И подскажите если стоит чего - учить, то что.

mutabor 03.06.2008 23:54

Не путай библиотеки с умением делать игры. Библиотека это инструмент, как у художника кисть. Если ты в принципе можешь сделать игру, не важно в чем, ты сможешь сделать ее и в OpenGL, естественно после того как научишься с ней работать. Простой пример: в справке Дельфи описаны все функции канвы, ты видел там пример игры? Вот и в мануалах к OpenGL не увидишь.
Нужно кстати поднять общий уровень программирования, не только что касается игр. А то элементарно будут технические проблемы подключения, импортирования функций и т.д.

Учить однозначно стоит, если в перспективе игры только под Windows, учи DirectX. Если больше интересует кроссплатформ, твой выбор - OpenGL.
Не хочешь вникать в детали, есть движки, к-рые многое делают за тебя. Тут правда придется учить интерфейс движка, но он обычно намного легче и более высокоуровневый чем "родной" интерфейс библиотек.

Beermonza 04.06.2008 16:12

Canvas.Draw
 
Цитата:

Сообщение от L_M (Сообщение 110060)
... при рисовании по канве возникает мерцание...

Это явление нелогичной последовательности операций. Обычно мы выводим графику через Canvas.Draw когда нам вздумается, в циклах множество раз и тп. Как происходит отображение графики в OGL и DX? ...строится кадр в буфере и только самой последней командой выводится видеокартой на экран. Если делать Flip (вывод буфера на экран) когда вздумается, то будет такое же мерцание, падение fps, и нагрузка на видеокарту многократно возрастет. Так вот, применительно к играм: канвой (Canvas.Draw) нужно пользоваться только при выводе готового кадра, а построение выполнять в буфере.

Канва для игр перспективной вообще в принципе быть не может, ...это только некоторые экземпляры не требующие быстрого вывода и большого fps: типа первой Цивилизации или древней Симсити, карточных игр, простейших шахмат и пр. могут быть на ней реализованы в качестве макета, первого теста, учебного пособия, для себя от нечего делать, или как еще угодно.

mutabor 04.06.2008 17:26

Шахматный интерфейс коня )))
 
Вложений: 1
Человек просил ход конем, выкладываю в уроках, может еще кому пригодится. Когда-то это должны были быть шашки, но теперь будут шахматы, конь уже есть )

anton14 04.06.2008 18:05

А можно еще вопрос? Как сделать, чтоб картинка (допустим через 5 сек) появлялась в разных местах (то там, то здесь). Представление имею как делать, но решил все же уточнить, Спасибо!

Kostia 04.06.2008 18:18

например так

if GetTickCount mod 5000 = 0 then form1.Canvas.Draw(random(100),rando m(100),pic);

Хотя правильнее было бы так

Код:

var
  time: integer;

procedure TForm1.FormCreate(Sender: TObject);
begin
  time:=GetTickCount;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if GetTickCount - time >= 5000 then
  begin
    form1.Canvas.Draw(random(form1.ClientWidth-pic.Width),
                      random(form1.ClientHeight-pic.Height),pic);
    time:=GetTickCount;
  end;
end;


Kostia 04.06.2008 18:57

Идту туда куда смотрю!!!
 
Вложений: 1
Дума не только мне было интересно как реализовать ходьбу человека туда куда он смотрит. Возьмем тот же Crimsonland где человечек смотрит на мышь и идет туда по нажатию кнопки W. По этому алгоритму можно реализовать полет пули.

Вспомним тригонометрию, уравнение окружности выглядит следующим образом:

x=cos(a);
y=sin(a);

Рассмотрим x и y не как точки, а как некий прирост по оси x и оси y.
Допустим что a=pi/4, то sin(pi/4)=sqrt(2)/2 и cos(pi/4)=sqrt(2)/2, это значит, что нам нужно из начала координат (0,0) сдвинуться по оси x и y на sqrt(2)/2 и поставить там точку.

А теперь задача с человечком. Допустим, что угол его взора равен a и нам необходимо изменить его координаты x и y так чтобы он пошел вперед.

x:=x+cos(a);
y:=y+sin(a);

чтобы он пошол назад

x:=x-cos(a);
y:=y-sin(a);

вот и все :)

zetrix 04.06.2008 20:18

Цитата:

var
time: integer;

procedure TForm1.FormCreate(Sender: TObject);
begin
time:=GetTickCount;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
if GetTickCount - time >= 5000 then
begin
form1.Canvas.Draw(random(form1.Clie ntWidth-pic.Width),
random(form1.ClientHeight-pic.Height),pic);
time:=GetTickCount;
end;
end;
извините, но мне кажется это бред...
чем оно отличается от этого:
Код:

//интервал таймера выставить в 5000

procedure TForm1.Timer1Timer(Sender: TObject); 
begin 
form1.Canvas.Draw(random(form1.ClientWidth-pic.Width), random(form1.ClientHeight-pic.Height),pic); 
end;


Kostia 04.06.2008 20:43

Цитата:

Сообщение от zetrix (Сообщение 110489)
извините, но мне кажется это бред...
чем оно отличается от этого:
Код:

//интервал таймера выставить в 5000

procedure TForm1.Timer1Timer(Sender: TObject); 
begin 
form1.Canvas.Draw(random(form1.ClientWidth-pic.Width), random(form1.ClientHeight-pic.Height),pic); 
end;


Отличие лишь в одном, ваш пример для конкретного случая, а мой для общего. Так уж меня научили, делать не одноразовые вещи, а универсальные. :)

mutabor 05.06.2008 12:47

Цитата:

извините, но мне кажется это бред...
И я того же мнения )
Или TickCount использовать или таймер, а то получается и то и другое и можно без хлеба.

Beermonza 05.06.2008 16:21

Цитата:

Сообщение от mutabor
Цитата:

Сообщение от zetrix
извините, но мне кажется это бред...

И я того же мнения )
Или TickCount использовать или таймер, а то получается и то и другое и можно без хлеба.

Зрите в корень господа! ...кто сказал что под каждое действие/явление/процесс/алгоритм нужно отдельный таймер? Если не таким образом как показал Kostia, то проще никак. Таймер задает минимальный интервал который отсчитывает такт, если понимаете что-то в электронике, то аналог этому - кварцевый генератор. Внутреннее условие с GetTickCount дает собственный отсчет для конкретного процесса. Одно из условий может управлять интервалом таймера (например изменение кадровки) и работой/остановкой последнего.

Код:

var
  time,time2,time3: integer;

procedure TForm1.FormCreate(Sender: TObject);
  begin
    time:=GetTickCount;
    time2:=GetTickCount;
    time3:=GetTickCount;
  end;

// интервал таймера меньше самой малой задержки в условиях
procedure TForm1.Timer1Timer(Sender: TObject);
  begin
    if GetTickCount - time >= 1000 then {процедура1}
    if GetTickCount - time2 >= 3000 then {процедура2}
    if GetTickCount - time3 >= 5000 then {процедура3}

    {процедура отрисовки}
  end;


mutabor 05.06.2008 18:24

И даже в этом случае TickCount юзать необязательно, достаточно переменной счетчика.

Конструкция с TickCount может заменить таймер (TTimer), когда вешается на Application.OnIdle. В остальных случаях есть таймер и его достаточно. А так получается двойная проверка, таймер тикнул, но мы ему не верим и проверим, а правильно ли он отсчитал? А кто проверит правильно ли TickCount отсчитал?

Beermonza 05.06.2008 19:31

Способов бывает много, причем один из равноценных не являются абсурдным. Если интервалы условий выбирать кратными интервалу таймера, то все работает как нужно, за исключением если вам конкретно нужно "полтора землекопа". Бреда здесь нет :)

L_M 08.06.2008 23:33

Эй, народ! Напишите еще пару уроков. Я еще начинающий, но большая часть того, что сдесь пишется(в этой теме) либо очень непонятна(когда начинают о чем-то своем спорить профессионалы) или очень простым и неинтересным. Я могу наверное сделать чего-нибуть несложное типа простых шашек, или змейки, или пазлов например. Но дальше не идет. Напишите например какую-нибудь игру типа "герой прыгает по платформам через весь уровень убивая плохих и собирая юонусы". Напишите, как вы бы создавали эту игру сами, но максимально просто, желательно вообще через канву. Например сначала движение главного героя и его гравитацию(разные пружки и пр.), потом удару главного героя и вообще какую-нибудь анимацию, потом загрузка уровня, потом расположение объектов, потом... Особое внимание уделите пожалуйста графике. Я думай это будет многим интересно, надеюсь я не один такой тупой. выручайте, люди. я в тупике - то что я могу сделать не приведет к моему прогрессу, а для остального я совсем не готов. я даже не знаю что конкретно можно спросить. Поэтому напишите еще пару уроков по созданию ИГР для НОВИЧКОВ.

Kostia 09.06.2008 05:39

http://www.programmersforum.ru/attac...2&d=1211033214
Это анимация. Стрелками влево, вправо, планета катится, как шар из боулинга.
Реализовать прыжки проще некуда. Заводите переменную sy, скорость по y и если под ногами у героя ничего нет, то прибавляем ускорение свободного падения к скорости, а по нажатию, прыжок, нужно просто sy присвоить какоенибудь отрицательное число, естественно если sy=0.
Ходьбу по платформам это тоже достаточно легко реализовать. Нужно проверить 4 точки героя на столкновение со всеми видимыми платформами(чтобы не тормозило). Две верхние и две нижние. Если одна из нижних столкнулась(если гг падает), то его sy:=0;, а если он подлетает, то нужно проверить, две верхние точки и при столкновении sy:=0; и тут гравитация притянет его к земле. При ходьбе влево вправо, тоже советую завести переменную sx, скорость по x. И проделать тоже самое, только точки нужно проверять слева и справа.
http://www.programmersforum.ru/showthread.php?t=20453, здесь описано как двигать экран.

Beermonza 09.06.2008 16:39

На канве...
 
Цитата:

Сообщение от L_M
... большая часть того, что сдесь пишется(в этой теме) либо очень непонятна(когда начинают о чем-то своем спорить профессионалы) или очень простым и неинтересным...

Простым оно кажется толко, если вы уже чему-то научились, это очень хорошо. А "споры" возникают только из-за хитровымудренности, каждый предлагает свой вариант, который использует, и это правильно. Ваша задача слушать и "впитывать". В жизни придется повстречаться с одними и теми же задачами, а вот заметить в них тонкости не удасться, если вы владеете только одним методом.
Цитата:

Сообщение от L_M
... Напишите например какую-нибудь игру типа "герой прыгает по платформам через весь уровень убивая плохих и собирая юонусы"....

Имеется в виду аркада. Написать готовое будет неверным с точки зрения самой темы, это как "препод, блин!, ...покажи ответ, немогу решить пример". Задача - научить Вас думать, и самостоятельно выбирать метод решения.
Цитата:

Сообщение от L_M
... Напишите, как вы бы создавали эту игру сами, но максимально просто, желательно вообще через канву...

Как работать с канвой было показано, Canvas.Draw применяется.

Вот вы утвердились, будет главный герой, он передвигается по уровням, прыгает, стреляет из оружия, собирает предметы убивает противников, ...типичная аркада.
Создавать игру нужно со "скелета" - модели уровня, модели объектов, системы хранения ресурсов и использования ресурсов. Я со своей стороны конечно предложу в качестве модели уровня - двумерный массив. Передвижение героя по "невидимым клеткам" со смещением для плавного перехода. Возможно реализация покажется сложной, ... что скажут остальные, какие еще есть предложения?

mutabor 09.06.2008 17:59

Если графика на канве, то самое главное отойти от использования компонента TImage. Многие новички динамически создают массивы из TImage и помещают их на форму. Далеко не лучший способ. Единственная польза - научишься динамически создавать VCL объекты, если это кому нибудь надо )
Продолжение следует ...

p/s Сегодня уже нет времени, завтра порассуждаю на эту тему )

L_M 09.06.2008 22:22

Ладно, тогда начнем. Вы предлагаете в качестве модели уровня двумерный массив. А что он будет хранить(из приведенного ниже)? Как связать проходимость(т.е. физику), свойства объектов и вывод графики? Массив имеется в виду на сколько: вся карта или по размеру экрана, где будут меняться данные при продвижении?

mutabor 10.06.2008 11:39

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

Beermonza 10.06.2008 18:11

Модель аркадного уровня
 
Вложений: 1
Пожалуй начнем.
Данный метод построения модели "игрового пространства" может быть с успехом применен для любых игр, как 2D, так и 3D.

Представте себе тетрадный лист в клеточку. Каждая клетка листа служит нам элементарной единицей пространства. Двумерный массив - математическая модель этого "тетрадного листа" (игрового пространства). Но в клетку массива обычно можно записать определенное значение некоторого типа. Для реализации множества параметров клетки (рисунок, проходимость, и пр.) потребуется "определить" эту клетку как собственный тип. Вот как это делается:
Код:

// тип модели уровня
Type
  TGameMap = object
  //-----------------
  TGTexture: TBitmap; {текстура}
  TGMove:    Byte;      {проходимость: 1 - нельзя, 0 - можно}
  //-----------------
end;

Теперь остается создать двумерный массив и задать ему выше указанный тип (пределы устанавливайте по усмотрению):

Код:

Var
  MapMas: array[0..39, 0..29] of TGameMap;

Все, модель готова.
Попробуем создать буфер кадра, в котором будет производиться построение, перед финальным выводом на экран, ... также загрузим картинки. Тут же построим игровой уровень, ...я покажу самый простой, статичный метод:

Код:

procedure TForm1.FormCreate(Sender: TObject);
begin
// создается буфер кадра
  BitBuf:=TBitmap.Create;
  BitBuf.Width:=800;
  BitBuf.Height:=600;
// размеры формы
  Form1.Width:=800;
  Form1.Height:=600;
// размер клетки
  cell:=20;
// загрузка картинок
  wall:=TBitmap.Create;
  wall.LoadFromFile('wall.bmp');
  brg:=TBitmap.Create;
  brg.LoadFromFile('brg.bmp');

// простейшим образом создается уровень
  for y:=0 to 28 do
    begin
      for x:=0 to 39 do
        begin
          if (y=28)
            or ((y=25) and (x>=5) and (x<=10))
            or ((y=23) and (x>=15) and (x<=20))
            or ((y=21) and (x>=25) and (x<=30)) then
            begin
              // картинка мостика, "в нем" ходить нельзя
              MapMas[x,y].TGTexture:=brg;
              MapMas[x,y].TGMove:=1;
            end
          else
            begin
              // картинка заднего фона, ходить можно
              MapMas[x,y].TGTexture:=wall;
              MapMas[x,y].TGMove:=0;
            end;
        end;
    end;

end;

В данном случае, карта будет ограничена снизу, и три полочки зададут некоторые объекты уровня. В последствии вам придется с помощью редактора создавать уровни, точнее их "скелеты", и в игре динамически подгружать.

Обновление кадра будет выполняться в таймере вот таким образом:

Код:

// обновление кадра
  for y:=0 to 28 do
    for x:=0 to 39 do
      BitBuf.Canvas.Draw(x*cell,y*cell,MapMas[x,y].TGTexture);

Теперь про сам вывод изображения на экран. Будем выводить прямо в форму, используем контекст Windows, для вывода данных. Процедура вывода:

Код:

// процедура вывода изображения на форму
procedure TForm1.WMPaint(var Message: TWMPaint);
begin
  DC:=Message.DC;
  If DC=0 then DC:=BeginPaint(handle,PS);
  Try
    BitBlt(DC,0,0,800,600,BitBuf.Canvas.Handle,0,0,SRCCOPY);
  Finally
      If Message.DC=0 then EndPaint(handle,PS);
  end;
end;

Вызов процедуры выполняется так:

Код:

// вывод изображения на экран     
  M.DC:=GetDC(handle);
  WMPaint(M);
  ReleaseDC(handle, DC);
  DeleteDC(DC);

Этот вызов должен выполняться в самом конце, после завершения построения кадра, всегда.

Вот в принципе и все с моделью игрового пространства. Дальше будем разбирать модель персонажа, при условии, что знатоки помогут найти более простой способ, или просто что-то предложат :)

mutabor 10.06.2008 21:03

Хочу сделать маленькое дополнение, в кач-ве заполнителя ячеек карты в простых играх можно применить обычный byte.
В программе эта карта будет иметь вид:
map: array of array of byte;
В файле карта будет иметь вид:
001012200...
003012200...
041015500...
...
Тип byte позволяет иметь до 256-ти различных видов "заполнителя" карты, чего в аркаде хватает с головой, обычно хватает и десяти. Если все же их больше десяти, то в файле массив будет иметь несколько другой вид, нужен разделитель - пробел.
0 10 12 0 1 2 2 0 0...
0 15 3 0 1 22 2 0 0...
0 4 1 0 1 5 5 0 0...
...

В заключение приведу реальный уровень из реальной игры Диггер (не оригинал, ремейк)
Цитата:

#1

0xxxgxxxxx0000M
0xxDDxxDxx0xgxx
0gxDDxxDxx0xxxx
0xxDDgxDgx0xDDD
0xxDDxxDxx0xDDD
00xDDxxDxx0xDDD
x0xxxxgxgx0xxxx
x0000xxxxx0xxxx
Dxxx0xxxxx0xxxD
DDxx000*000xxDD

Из этой же игры, уровень для другого режима игры
Цитата:

#1

MonstrMax=3
MonstrGun=0
MonstrRed=0
LifeStart=5345
LifePer=599
CherryStart=2000
CherryPer=356
SlowStart=2890
SlowPer=1234
TeleportStart=8800
TeleportPer=888
Fon=00.bmp

DDxxxxMxxxxxxDxxxxDD
Dxxxxg0gxxxxxDxxxxxD
xggxxx0xxxxxxDxxxggx
xxxxxx0xxxxxxDxxxxxx
xxxxxx0xxxxxxDxxxxxx
DDDDDD00000000000000
xxxxxx0DDDDDD0xxxxxx
xxxxxx0DDDDDD0xxxxxx
*0000000000000DDDDDD
xxxxxxDxxxxxx0xxxxxx
xxxxxxDxxxxxg0gxxxxx
xggxxxDxxxxxx0xxxggx
DxxxxxDxxxxxx0xxxxxD
DDxxxxDxxxxxxMxxxxDD


mutabor 10.06.2008 21:20

Цитата:

Сообщение от Beermonza (Сообщение 112711)
// тип модели уровня
Type
TGameMap = object
//-----------------
TGTexture: TBitmap; {текстура}
TGMove: Byte; {проходимость: 1 - нельзя, 0 - можно}
//-----------------
end;

А не лучше сделать указатель на текстуру? Ведь если на карте много клекток с одинаковой текстурой, трава например, незачем в каждом объекте хранить ее копию.

p.s. А-а, все, увидел: MapMas[x,y].TGTexture:=brg;
По сути тот же указатель. Битмап будет просто ссылаться на другой битмап (здесь на brg).

Продолжение (про карту of byte)
Как же загружать картинки при такой карте? Очень просто. Создаем массив битмапов, или же используем стандартный контрол TImageList. Загружаем в него картинки так, чтобы их нумерация совпала с элементами карты. Т.е. если у нас трава в карте это 0, то и картинка с травой тоже должна иметь индекс 0.

Kostia 11.06.2008 10:15

Вложений: 1
L_M, заказывали пример, вот, получите и распишитесь. :) Небольшая игра по типу лабиринта, если усовершенствовать.
Управление: left,up,right,down.
Цель: добраться до конца уровня к маленькому квадратику.
Будет время, выложу пример аркады, в которой прыгать нужно, в этом же стиле. Как прикрутить картинки, тебе уже рассказали. :)

Kostia 11.06.2008 12:22

Вложений: 1
Вот и второй пример поспел к раздаче. :) игра похож на предыдущую, только теперь она похожа на стандартную игру на Nokia, где мячик прыгает.
Управление: left,right,space.
Цель: добраться до маленького квадратика.

Офф-топ: я завтра уезжаю на две недели, не теряйте. =)

L_M 11.06.2008 22:08

Спасибо всем. А про TImageList объясните: что такое, зачем использовать(а не массив), как пользоваться. И почему модель уровня описана как объект, а не например просто запись?

mutabor 11.06.2008 23:26

TImageList это и есть массив, никаких особых преимуществ он не даст, просто один из способов. Польза есть в обоих случаях, в первом научишься использовать TImageList (он пригодится в прикладных программах), во втором научишься создавать динамические массивы, в частности из битмапов (тоже полезно =).
Как пользоваться написано в справке и в книгах по Дельфи. Не отходите от темы )

Beermonza 12.06.2008 17:24

Цитата:

Сообщение от L_M (Сообщение 113166)
... И почему модель уровня описана как объект, а не например просто запись?

Это я вырезал кусочек из своего кода, так было нужно, ...можете описать как угодно, packed record.

Не вижу смысла использовать ImageList, чтобы оставить его пустым, и при запуске заполнять эго картинками, ...или может загрузить картинки сразу и хранить в EXE? , побойтесь Бога.

Вот такой вариант мной применялся до недавнего времени:

Код:

Var
  Tex: TBitmap;
  i, n: Byte;
  TexMas: array[1..255] of TBitmap;
...

procedure TForm1.LoadTexture;
begin
// n определяется сразу, если вы точно знаете сколько будет текстур
// у меня было считывание из системного файла.
  for i:=1 to n do
    begin
      Tex:=TBitmap.Create;
      Tex.LoadFromFile(IntToStr(i)+'.bmp');

      {тут были манипуляции с текстурами}

      TexMas[i]:=Tex;
    end;
end;

Теперь при построении уровня узнаем индекс и выдергиваем из массива текстур нужную картинку.
Почему модель описана собственным типом? Конечно, то, что было показано - упрощенный вариант, ...а бывает, что можно не только проходить или нет, но и проходить с потерями, например если в клетке стоит огонь, или вода, ...в общем параметров может быть очень много (у меня 48).

Цитата:

Сообщение от mutabor
...Тип byte позволяет иметь до 256-ти различных видов "заполнителя" карты, чего в аркаде хватает с головой, обычно хватает и десяти. Если все же их больше десяти, то в файле массив будет иметь несколько другой вид, нужен разделитель - пробел.
0 10 12 0 1 2 2 0 0...
0 15 3 0 1 22 2 0 0...
0 4 1 0 1 5 5 0 0...

Разделителей не нужно, если использовать тип Byte как положено, ...это 0-255 символов латинского, русского алфавитов, включая числа и символы. Т.е. нужно задействовать кодировку ASCI, с одним условием, что символ под кодом 26 применять не следует, он означает "конец файла", если в цикле будут считываться символы, то на символе Chr(26) файл будет закрыт преждевременно.
Так вот, при этой системе размер файла будет в разы меньшего объема, и плюс, нужно считывать подряд байт за байтом. Вот что может быть в файле:
кЩxХС®AТ•Ф
—dЌmҐEzA•˜№
UbJЃм•мп/¤
Л**@UMCtmЇ
...а теперь представьте как это выглядит с пробелами и по 2-3 байта на одну клетку карты. Никаких прочих алгоритмов писать не нужно, просто банальное read. Вот пример считывания карты с текстового файла:
Код:

Var
  c: Char;
  MapFile: TextFile;
...
AssignFile(MapFile, 'map.txt');
Reset(MapFile);
While not EOF(MapFile) do
  begin

    // тут условия как рассчитывать размеры двумерного массива
    // каким образом придаются значения x и y, сразу, или же из этого же файла

    Read(MapFile, c);
    MapMas[x,y].TGTexture:=TexMas[Ord(c)];
  end;
CloseFile(MapFile);
...

Если заметите ошибки в коде отметьте, приходилось упрощать готовый сложный код.

mutabor 12.06.2008 19:15

Ошибок нет, просто дополню до рабочего варианта
Код:

Var
  c: Char;
  MapFile: TextFile;
  w: integer; //ширина карты
  i: integer; //счетчик
...
AssignFile(MapFile, 'map.txt');
Reset(MapFile);
i:=0;
While not EOF(MapFile) do
  begin
    Read(MapFile, c);
    MapMas[i mod w, i div w].TGTexture:=TexMas[Ord(c)];
    Inc(i);
  end;
CloseFile(MapFile);
...


Beermonza 12.06.2008 22:12

Отлично! Идем дальше, ...уровень построить можно, Kostia показал метод управления "персонажем", ...показываем методы выполнения анимации, конкретно система (как загружать картинки и куда выше было показано), смело несколько вариантов, чтобы видеть сходства и различия, причем помним, что анимация на прыжки и передвижения отдельная, там же и прочие типы.

mutabor 13.06.2008 15:34

Мне кажется тут все предельно просто и реализации отличаться будут лишь деталями.

Для начала как хранить спрайты? Я знаю три способа: прямоугольная карта, в один ряд и отдельными файлами.

Я делал отдельными файлами, на то время с другими способами у меня были некоторые проблемы =) Грузил их в массив, и потом в таймере крутил, нужно скорость смены спрайта так расчитать чтобы было похоже что персонаж идет, а не семенит ногами на месте или чешет семимильными шагами. Для этого или подобрать интервал таймера, или же использовать счетчик.
Код примерно такой:
Код:

var
sprites: array of TBitmap;
i: integer; //счетчик
n: integer; //номер спрайта

//Timer
begin
Inc(i);
{тут код получения номера спрайта на основании счетчика
и направления движения}

//вывод нужного спрайта на экран в нужном месте
Draw(x, y, sprites[n]);
end;

Вот спрайты движения медведя влево, сам делал из мультика:

http://avoreg.ru/pic_b/17bfe862ac900...c4d1f6aebd.gif

Beermonza 14.06.2008 15:10

Не совсем понял, GIF-анимация применяется?

mutabor 14.06.2008 19:32

Цитата:

Сообщение от Beermonza (Сообщение 114037)
Не совсем понял, GIF-анимация применяется?

Нет, это я из спрайтов GIF смастерил, чтобы к сообщению прилепить.

Beermonza 15.06.2008 18:04

Значит есть смысл пояснить, как работает система смены анимации, если на каждое состояние персонажа свой набор кадров. К примеру, у нас 10 кадров на каждое состояние (пусть будет качество :) ).

Анимация персонажа (файлы bmp):
1-10 - стоит;
11-20 - приседает;
21-30 - идет влево;
31-40 - идет вправо;
41-50 - прыгает влево;
51-60 - прыгает вправо;
61-70 - стреляет (бьет) влево;
71-80 - стреляет (бьет) вправо;

Можете сделать меньше кадров, кому как нравится, или точнее, кому как ленится. Зеркальное отражение одного и того же действия я умышленно не применяю, и вам того же советую.
Создайте в проекте новую папку, обзовите как-угодно и поместите туда все файлы. Подгружаются все кадры подряд через цикл, который уже был показан ранее.
Теперь вызов нужной секции кадров из массива сводится к такому способу:

BitBuf.Canvas.Draw(x, y, sprites[t+n]); где: t - задает тип анимации, а n - номер кадра. Теперь нужно будет только прописать назначение типа t на клавишах, какой тип нужно показывать.

L_M 15.06.2008 22:25

Ну с этим вроде понятно, хотя я сейчас на анимацию вообще плюнул и у меня, так же как и в примере, двигается шарик. Расскажите, как:
1.организовать бонусы, конкретно как они будут воздействовать на персонажа.
2.враги, как организовать их движение: сделать тупо чтобы ходили вперед-назад, или чтобы шли к игроку?
3.карта-ее основа двумерный массив, но как подобрать размер? И быть с динамичными объектами: бонусами, монстрами и пр. Записывать их в массив или проверять по координатам?(их будет не много)

L_M 15.06.2008 22:29

кстати, а как насчет цикличности анимации? типа пакмана-открывает и закрывает рот-надо рисовать каждый кадр или, например, менять n:=-1?

mutabor 15.06.2008 22:52

Между открытым и закрытым ртом хотя бы два промежуточных положения должно быть. Нужен счетчик в таймере, когда счетчик достиг числа спрайтов, обнуляй его. В случае с пакманом можно схитрить, закрывает рот он также как и открывает, так что можно для закрытия спрайты не делать, а использовать те же только в обратном порядке:
Код:

var
n: integer = -2;
c: integer = 4; //кол-во спрайтов для одного движения рта (открыт, полуоткрыт,
//полузакрыт, закрыт)
...
begin
Inc(n);
if n > 3 then n:=-2;
BitBuf.Canvas.Draw(x, y, sprites[t+Abs(n)]);
end;

2 Beermonza, я не так смену кадров делал, просто высчитывал номер. Например всего 24 спрайта, 4 направления по 6 спрайтов.
n - номер спрайта
i - счетчик (1 - 6)
d - направление (0 - 3)
n := d * 6 + i;

mutabor 15.06.2008 23:03

Цитата:

1.организовать бонусы, конкретно как они будут воздействовать на персонажа.
Как ты придумаешь, так и будут. :confused:
Цитата:

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

3.карта-ее основа двумерный массив, но как подобрать размер? И быть с динамичными объектами: бонусами, монстрами и пр. Записывать их в массив или проверять по координатам?(их будет не много)
Монстров в массив (но не в карту, если ты это имел ввиду) и по координатам проверять столкновение, а как же еще.
Monsters: array of TMonstr;
А что с картой? В каком смысле подобрать размер?

Beermonza 16.06.2008 14:50

Думаю, имеется в виду, если карта больше экрана, как корректно сдвигать карту относительно него. Тут карты могут быть любого размера, главное помнить размеры, и держать персонажа по центру экрана.

L_M 18.06.2008 22:02

нет, я имею в виду, что вот установлю я разрешение 800*600 и какими делать квадраты?(при полноэкр. режиме)
бонусы я не знаю как сделать. Например ускорение-если увеличивать сдвиг, будет получаться несоответствие с анимацией, сложности с проверкой столкновения и проч.
еще вопрос: что делать при смерти перс.? Ну я имею ввиду как это делать. Отключать таймер и писать Game Over? А заново? И вообще как организовать меню?

Beermonza 19.06.2008 21:10

Цитата:

Сообщение от L_M
нет, я имею в виду, что вот установлю я разрешение 800*600 и какими делать квадраты?(при полноэкр. режиме)

Размеры у вас не в единицах метрики, а в конкретных пикселах. Что произойдет если в Windows сменить разрешение с 1024x768 на 800x600? ...останутся ли иконки прежнего размера? Вы имеете дело не с Direct3D, где изменив разрешение получите те же размеры объектов но уже с более крупными пикселами.

Цитата:

Сообщение от L_M
...бонусы я не знаю как сделать. Например ускорение-если увеличивать сдвиг, будет получаться несоответствие с анимацией, сложности с проверкой столкновения и проч.

Создайте выражение, главный параметр - скорость анимации, это интервал таймера анимации, значение выражения - сдвиг, на который смещается персонаж. Уравняйте так, чтобы совпадало со скоростью анимации скорость перемещения персонажа.

Цитата:

Сообщение от L_M
...еще вопрос: что делать при смерти перс.? Ну я имею ввиду как это делать. Отключать таймер и писать Game Over? А заново? И вообще как организовать меню?

Начальные параметры следует хранить в отдельных массивах записей, при выполнении определенных условий "смерть", "начать сначала", "конец игры", нужно считывать записи и выполнять процедуру обновления игрового мира - это банальное присвоение текущим значениям переменных состояния игрового мира тех, что находятся в записях. Папример, у вас персонаж появляется в некоторой точке при запуске игры - это тоже два параметра X и Y, они должны быть в записях по-умолчанию. Нужна масса параметров, которые четко описывают состояние игрового мира (повторюсь, у меня их 48, ...где кто находится и что делает).

Меню игры (интерфейс) выполнить легче всего на панельках (Panel), которые могут содержать графику, кнопки, ...да все, что угодно.

L_M 19.06.2008 22:02

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

L_M 19.06.2008 22:14

Вложений: 1
вот я попробовал написать игру и что получилось. теперь я думаю надо добавить разные детали уровня вместо простых кубиков, персонажей, анимировать, добавить звук, меню, бонусы, сделать редактор карт. Вроде все.
P.s. оцените что я сделал, только не дотрагивайтесь до врагов, потому что на прикосновение я поставил вывод сообщения, что бесконечно. стрелки-идти и прыгать, пробел-стрелять, врагов можно убить, 3 уровня

Карась 19.06.2008 22:52

В архиве недостаточно файлов для запуска. Скиньте весь проект.

L_M 20.06.2008 22:01

Вложений: 1
извините, я забыл сами уровни. Также я сделал редактор, правда он рисует одно и то же, но работает правильно(таб-для ввода названия уровня, когда написал название нажать энтер, кликать мышкой, по умолчанию рисуется стена, после нажатия цифры 1 рисуется стена, 2- нач положение перс, 3- конец, 4-враг)

Kostia 22.06.2008 15:24

Привет всем :)
 
Вложений: 2
Меня небыло 2 недели, а тут почти ни каких продвижений в Gamedev'е.
L_M, пока плоховато.
У меня после пары запусков, все иконки с рабочего пропали, это может быть вызвано, не правильной очисткой памяти или ее не очисткой. При выходе вылетает ошибка, пока еще не разбирал код, но мне кажется что ты чего не создал, а потом пытаешься его использовать или освободить его память. Пока с освобождение памяти можешь не мучаться, все за тебя delphi сделает.

Меня затянул мой предыдущий пример и я захотел улучшить его, гляньте что получилось. Разрешение 320*240, fullscreen. Когда запустил игру в таком режиме, я снова вспомнил когда мне было 6 лет и денди к черно-белому телеку подключенный. Короче прикольная игрушка, от которой веет стариной, получилась.

Управление: Left, Right, up или space.
Цель: собрать зелененькие шарики и добраться до двери.
Описание: вы играете маленьким шариком. Вам нужно пройти лабиринт с ловушками и собрать зеленые шарики и пройти на следующий уровень через дверь. В лабиринте вам встретятся разные ловушки: электрические ловушки, шипы и батуты которые не всегда будут вам помогать.

Kostia 22.06.2008 21:51

У меня предложение. Эта тема начинает превращаться во свалку с неоднократно повторяющимися вопросами и ответами, все уроки разбросаны как попало, что приходится листать страничку за страничкой и в поисках полезной инфы, а вместо нее только каша информации.
Предлагаю создать две темы:
Уроки по созданию игр для новичков... - здесь будут лежать исключительно уроки, без вопросов и объясните пожалуйста. Одним словом очистить это тему от лишнего.
Мучающий меня вопрос... - здесь кто не попадя сможет задать вопросы, получать на них ответы, показывать свои наработки и обсуждать различные нюансы по созданию игр. И хорошие ответы из этой темы будут перетекать в тему выше.
Думаю так будет логичнее всего поступить.

mutabor 24.06.2008 03:05

Не так уж много страниц тут, за день прочитать можно, а игры то не за день делать учатся, так что постепенно можно прочесть. Для новичка тут все полезное, в том числе споры "более продвинутых товарищей". Это вообще эксклюзив, ни в одной книге не прочтешь )

Хотя в чем-то ты прав, тема не так начинала свою жизнь, но надо смотреть на это как на естественную эволюцию.

Beermonza 24.06.2008 23:02

Поддерживаю систематизацию уроков, но и "вариации на тему" в подавляющем большинстве своем - незаменимый урок начинающему, как правильно понять сее теоретическое и как применить правильно с нужной выгодой в тех или иных случаях.

Kostia 25.06.2008 09:15

Цитата:

Для новичка тут все полезное, в том числе споры "более продвинутых товарищей". Это вообще эксклюзив, ни в одной книге не прочтешь )
Согласен что здесь все полезно, но ведь споры можно вести и в другой теме. Человек прочитал урок и у него назрел какойто вопрос или он не понимает в нем что-то, то он задает все вопросы в теме "Мучающий меня вопрос..." где ему ответят "Эксперты" и этот ответ пойдет в урок, естественно в обработанной форме и станет частью урока. Таким образом будет и порядок и уроки будут совершенствоваться в лучшую сторону и становиться более полными.

L_M 28.06.2008 22:25

просто уроков не слишком много. да и тогда весь этот раздел можно было уместить в двух-трех темах(кстати что правильно). а у меня такой вопрос: как обрабатывать и действоовать с объектом, если он никак не умещается в 1 клетку карты? например он должен в массиве занимать несколько клеток, а при считывании как определить с какой клетки начинать рисование? ну для рисования объект можно разделить, а как быть например с удалением этого объекта, т.е. правильно найти все его части и удалить, ведь рядом могут быть несколько одинаковых объектов?

mutabor 29.06.2008 15:26

У объекта должны быть координаты, то есть Left, Top (в клетках или в пикселях неважно). Ну и габариты. Вот и все. А клетки на поле занятые объектом маркируются соответсвующе.
Если он большой то и рисовать его целиком, делить незачем.

Kostia 29.06.2008 15:51

Думаю пришло время изучить более простую но продвинутую конструкцию карт. Это карта путей. На подробное описание времени нет, но скажу что это 2D массив типа boolean(можно byte если будут плохо проходимые места, но принцип один) 0-проходимая клетка, 1-не проходимая и делать то что написал mutabor.
Например у нас есть дом 2*2 клетки и он стоит в x и y координате. Мы при загрузки карты считываем координаты дома и циклом заполняем соответствующие клетки карты путей единицами и просто рисуем там дом.
Подробнее и с примером отпишусь чуть позже.

Beermonza 29.06.2008 16:27

На 11-й странице про проходимость рассказывалось, даже тип был создан для этого, чтобы в одном массиве хранить индексы и графики и карты проходимости.

Beermonza 29.06.2008 16:40

Цитата:

Сообщение от L_M (Сообщение 118258)
...как обрабатывать и действоовать с объектом, если он никак не умещается в 1 клетку карты? ...

Если есть объект, то он должен, иметь размеры, ...и рекомендую также - смещение относительно начала изображения. Например, клетка у нас 20х20 пикселей, а объект 30х30 пикселей, ...так вот, "номер" клетки в массиве мы знаем, допустим это [5,6], а смещение в пикселах поможет нам правильно отрисовать объект в нужном месте, т.е. для 30х30, смещение будет -5 и -5 по осям X и Y, соответственно, для расположения в центре клетки карты 20х20.
Значит, благодаря смещению мы правильно отображаем объект, а благодаря размерам - правильно проверяем объекты на столкновения. Создайте свой тип на объект, где будут записи на ширину и высоту картинки, смещение по осям X и Y, и еще много чего вам будет полезно, например состояние персонажа, номер анимации, текущий кадр и пр. пр. пр.

L_M 01.07.2008 23:12

извините, но я не понимаю преимуществ карты путей. зачем делать тот же массив, еще и сложнее: добавлять разные свойства, рисунок и пр. массив чисел мне кажется проще-только для каждого числа свои действия. а ту же проходимость например можно сделать так:
if map[i,j]>n then Go;
где до n непроходимые рисунки, а после - проходимые.

L_M 01.07.2008 23:13

не примите как возражение против карты путей, просто объясните, в чем преимущество?

Beermonza 02.07.2008 19:12

Цитата:

Сообщение от L_M (Сообщение 118950)
... объясните, в чем преимущество?

В универсальности. Вы с легкостью сможете применять специальные бонусы, типа "прохождение стен", "хождение по воде", причем они между собой не стыкуются. Бывают моменты, когда необходимо просто сменить карту проходимости, оставив при этом все текстуры на местах как были. Мало ли что потребуется в будущем. Использование же Case внутри программы вам только добавит проблем, и от универсальности не останется и следа.

ORBIUS 17.07.2008 09:02

А кто может сказать как загрузить на форму свою анимацию?

Beermonza 17.07.2008 15:32

ORBIUS, а что вы подразумеваете под "загрузить на форму анимацию"? ...где хранить кадры или как их выводить на экран?

ЛомиК 18.07.2008 13:09

Цитата:

Сообщение от Beermonza (Сообщение 123609)
ORBIUS, а что вы подразумеваете под "загрузить на форму анимацию"? ...где хранить кадры или как их выводить на экран?

Йа думаю, он имел ввиду - где хранить кадры, и как их выводить на экран...:rolleyes:
Вот странные люди программисты, толи делают вид, что непонимают, чего может непонимать спрашивающий, толь ленятся больше одного ответа давать.
Интересует то весь процесс с максимальным количеством подробностей и с примером, если можно, а не совет, дави F1...:rolleyes:

Titan123 18.07.2008 14:35

пишу танчики и просто застрял на одном месте!
как можно сделать, чтобы если, ты, например, развернут вниз, компонент image1 (снаряд) летел вниз, вправо-вправо и т.д.
у меня все время он летит вверх, чтобы я не делал!

я задал переменные:
Код:

image3up,image3left,image3down,image3right:boolean; //image3-снаряд
  image2up,image2left,image2down,image2right:boolean;//image2-танк

далее обрабатываю кнопку "выстрел":
Код:

if image2up=true then
begin
image3up:=true;
image3left:=false;
image3down:=false;
image3right:=false;
image3.Left:=image2.Left+15;
image3.Top:=image3.top-15;
end;

и так для всех случаев.

в таймере пишу код:
Код:

if image3up=false then
begin
image3.Top:=image3.Top-7;
end;
if image3right=true then
begin
image3.Left:=image3.Left+7;
end;
if image3left=true then
begin
image3.Left:=image3.Left-7;
end;
if image3down=true then
begin
image3.Top:=image3.Top+7;
end;

все равно снаряд летит вверх и только туда
помогите, плиз, так хочется по-скорей закончить, а тут это... :(

Beermonza 18.07.2008 17:04

Популярно...
 
ЛомиК, ярлыки вешать все мастера.
Обычно так и происходит на полное описание процесса потом идет нарекание типа "это я и без вас знаю, мне бы вот это...", ...так стоит ставить вопрос соответствующе, чтобы было понятно, что имеется в виду. Загрузить на форму - это одно, вывести на форму - это другое. А за примеры не боИтесь, без них не оставляем :cool:
Все взято из тем "Как вы относитесь к созданию игр на Delphi?" и "Уроки по созданию игр для новичков". Вывод графики для VCL, загрузка, и структура хранения без ограничений для любых методов.

Создание структуры хранения анимации

(это было к примеру аркады, "Уроки по созданию игр для новичков", пост #115)

Если на каждое состояние персонажа свой набор кадров. К примеру, у нас 10 кадров на каждое состояние (пусть будет качество).

Анимация персонажа (файлы bmp):
1-10 - стоит;
11-20 - приседает;
21-30 - идет влево;
31-40 - идет вправо;
41-50 - прыгает влево;
51-60 - прыгает вправо;
61-70 - стреляет (бьет) влево;
71-80 - стреляет (бьет) вправо;

Можете сделать меньше кадров, кому как нравится. Зеркальное отражение одного и того же действия я умышленно не применяю, и вам того же советую.
Создайте в проекте новую папку, например Anim, и поместите туда все файлы.

Загрузка анимации

Практикуется загрузка анимации в ImageList.
("Уроки по созданию игр для новичков", из поста #109)
Не вижу смысла использовать ImageList, чтобы оставить его пустым, и при запуске заполнять эго картинками, ...или может загрузить картинки сразу и хранить в EXE? , побойтесь Бога.

Загружать анимацию будем в массив типа TBitmap.
Вот такой вариант мной применялся до недавнего времени:
(добавлю точности для частного случая)

Код:

Var 
  Tex: TBitmap;
  i, n: Byte; 
  TexMas: array[1..255] of TBitmap;
 
... 

procedure TForm1.LoadTexture; 
  begin 
    // n определяется сразу, если вы точно знаете сколько будет текстур анимации
    // у меня было считывание из системного файла. 
    for i:=1 to n do 
      begin 
        Tex:=TBitmap.Create; 
        Tex.LoadFromFile(GetCurrentDir+'\Anim\'+IntToStr(i)+'.bmp'); 

        {тут были манипуляции с текстурами} 

        TexMas[i]:=Tex; 
      end; 
    end;

Эта процедура выполняется в самом начале один раз. Каждая ячейка массива TexMas будет содержать определенную картинку определенного типа анимации.

Подготовка кадра

("Уроки по созданию игр для новичков", из поста #85)
Цитата:

Сообщение от L_M
... при рисовании по канве возникает мерцание...

Это явление нелогичной последовательности операций. Обычно мы выводим графику через Canvas.Draw когда нам вздумается, в циклах множество раз и тп. Как происходит отображение графики в OGL и DX? ...строится кадр в буфере и только самой последней командой выводится видеокартой на экран. Если делать Flip (вывод буфера на экран) когда вздумается, то будет такое же мерцание, падение fps, и нагрузка на видеокарту многократно возрастет. Так вот, применительно к играм: канвой (Canvas.Draw) нужно пользоваться только при выводе готового кадра, а построение выполнять в буфере.
(пост #102)
Попробуем создать буфер кадра, в котором будет производиться построение, перед финальным выводом на экран:

Код:

procedure TForm1.FormCreate(Sender: TObject); 
begin 
  // создается буфер кадра 
  BitBuf:=TBitmap.Create;
  // размеры буфера 
  BitBuf.Width:=800; 
  BitBuf.Height:=600; 
end;

Теперь вызов нужной секции кадров из массива сводится к такому способу:

Код:

BitBuf.Canvas.Draw(x, y, TexMas[t+n]);
где: t - задает тип анимации (смотрим таблицу, при нажатии клавиш в t записываем число), а n - номер кадра (таймер TTimer считает от 1 до 10). x и y - координаты персонажа на игровом поле.

Вывод анимации

Тут следует уточнить, куда выводить анимацию, прямо на форму или же в PainBox, Image. Пусть в Image. Смотрим процесс отрисовки кадра и его вывод в Image в процедуре таймера:

Код:

procedure TForm1.Timer1Timer(Sender: TObject);   
begin
  // подготовка кадра
  BitBuf.Canvas.Draw(x, y, TexMas[t+n]);
  // вывод на экран 
  Image1.Picture.Bitmap.Canvas.Draw(0,0,BitBuf);   
end;

А если персонажей много? ...начинаем с модели мира.
(читаем материал "Уроки по созданию игр для новичков", пост #102)
Создаем свой тип для модели мира (уровня) и для персонажей, в таймере применяем цикл по числу персонажей.

P.S. Если нужно, остановимся подробнее на модели персонажа.

Beermonza 18.07.2008 17:34

Titan123, для начала слегка поменяйте название переменных, ...человеческий зрительный аппарат так устроен, что привыкает к похожести начальных нескольких символов, и при беглом поиске просто считает имена одинаковыми, ...в итоге поиск ошибок затрудняется. Это из многолетней практики.
Предложу исправить вот так:
Код:

PatronUp, PatronLeft, PatronDown, PatronRight: Boolean; //PatronImage-снаряд 
TankUp, TankLeft, TankDown, TankRight: Boolean; //TankImage-танк

С условиями понятно, вас интересует только состояние флагов TRUE, т.е. находится ли снаряд в нужной позиции, остальные направление - false. Смотрите внимательно обработку кнопок.
Также в таймере есть условие: if image3up=false then оно неверное, если вас интересует лишь истинность True. ...это наверное попытка хоть как-то повлиять на ситуацию? :)

mutabor 18.07.2008 17:35

Titan123, раз он все время летит вверх, эначит этот код
Код:

if image3down=true then 
begin 
image3.Top:=image3.Top+7; 
end;

не выполняется, иначе летел бы вниз. Или же выполняется, но перекрывается другим кодом где происходит обратный процесс.
Чтобы не было таких запутанных условий, лучше сделать немного иначе:
Код:

type
TDirection = (dLeft, dUp, dRight, dDown);

var
Direction: TDirection;

то же самое можно записать иначе
Код:

var
Direction: byte; {где 0 - left, 1 - up, 2 - right, 3 - down}

Так всегда будет однозначность, направление может быть только одно. В отличие от того способа, что у вас был, если неправильно обработать флаги он может лететь одновременно на все четыре стороны, в конечном итоге он полетит в одну, куда вектор тяги перевесит =)

ЛомиК 18.07.2008 18:18

Titan123, а кто снаряд? -

как можно сделать, чтобы если, ты, например, развернут вниз, компонент image1 (снаряд) летел вниз, вправо-вправо и т.д.
у меня все время он летит вверх, чтобы я не делал!

я задал переменные:

Код:
view plaincopy to clipboardprint?
image3up,image3left,image3down,imag e3right:boolean; //image3-снаряд
======
У Вас там путаницы с image нет? Правильно Вам посоветовали с именами переменных.

Beermonza

Извиняюсь, если задел, просто часто уж приходится слышать весьма лаконичные ответы, Вы мне открыли глаза, я и недумал что это может напрягать, хотя если человек совсем бестолков, тогда да, но я таким вообще не отвечаю, прошу прощенья.

L_M 18.07.2008 21:43

1.подскажите как лучше делать иск. интеллект? я вот пробовал для крестиков-ноликов описать процедуру постановки знака и вызывал ее с параметрами(чей ход и пр.) - т.е. как бы общая процедура для всех, а в процессе поиска лучшего решения я как бы моделировал ходы- комп проверял возможный ход на эффективность и проверял что будет. правилен ли такой подход или надо как - то иначе?
2. расскажите как сделать игру через интернет

Beermonza 19.07.2008 22:20

L_M, так понимаю, вам нужно написать искусственный интелект для некоторой игры: "расскажите как сделать игру через интернет", а первые попытки у вас были на игре "крестики-нолики"? ...или ваша игра "крестики-нолики" и вас не устраивает тот метод работы ИИ что вы уже применили?
Все зависит от типа игры и от поведения объекта, который вы собираетесь имитировать. Уточните, тогда можно будет вам помочь.

L_M 20.07.2008 21:39

ну конкретно я хочу сделать юнита, например в стратегии. вот вопросы:
1. как их все хранить? есть юнит, 1 штука, например объект. как хранить много юнитов(в массиве что ли)?
2. как создавать(динамически?).
3. как сделать прозрачные панели, например со зданиями?

L_M 20.07.2008 21:42

вот, забыл самое главное: нужно ли делать каждый юнит екземпляром объекта(класса, компонента,...) с процедурами, или описать глобальные процедуры, например движения и передавать туда параметры каждого юнита?

Titan123 21.07.2008 10:17

Цитата:

Сообщение от Beermonza
для начала слегка поменяйте название переменных, ...человеческий зрительный аппарат так устроен, что привыкает к похожести начальных нескольких символов

ну какая разница как названы переменные? не в этом дело то...

а вообще выше описанный мною способ с image3up и т.д. я нашел в одном исходнике. поэтому я даже не понимаю как это работает! может, надо как-то описать это... но как?
для меня идеальный способ был бы сказать если image2.picture='вверх.bmp' то...
но я узнал так сделать невозможно :(

может вы подскажите мне вообще альтернативный вариант этого действия? был бы очень признателен

Titan123 21.07.2008 11:35

все понял я.
как обычно, виноват я: запутался и допустил ошибки. всем спасибо. я, наверное, еще обращусь :)

Beermonza 21.07.2008 23:14

Про модель юнитов
 
Titan123, самый верный способ не допускать ошибки - это делать код как можно понятнее, даже для себя, писать комментарии, давать названия, из которых сразу видно что это и для чего. Даже если не это стало причиной неправильной работы программы в вашем случае, не соблюдение вышеуказанных правил вам еще о себе напомнит, когда вы будете писать проект не на десяток строк.

L_M, воу, воу, воу, не все сразу :) ...и ИИ, и модель юнитов, и графика, ...давайте по степени значимости. На первом месте всегда модели. Значит разбираем модель юнита (персонажа), полагаю модель мира вы уже понимаете как создается из прошлых уроков, даже готовую игрушку показали :) Для стратегии все аналогично, только текстурки тайлов будут изометрические или вид сверху.

Модель персонажа


Чтобы юнит был не один, нужно воспользоваться одномерным массивом, размер его нужно задать сразу, например (0-255) - это будет лимит "населения" в вашей стратегии. Массив создается сразу, а вот управлять его содержимым мы будем динамически.
Юнит обладает рядом характеристик игровых, а так же множеством системных данных от указателей на анимацию до индексов действий. Главным остается правило: "все юниты в системе игры имеют один и тот же набор характеристик и системных данных". Для этого нам понадобится собственный тип массива:

Код:

// тип "юнит" -----------------------------------------------------
  TGUnit = packed record
// флаг использования
    UUses: boolean;
// тип юнита
    UType: byte;
// имя юнита
    UName: string;
// обзор (когда юнит "замечает" цель)
    UScan: word;
// атака юнита
    UAttack: byte;
// дистанция атаки
    URange: byte;
// защита юнита
    UArmor: byte;
// максимальное количество жизней
    UHpMax: word;
// текущее количество жизней
    UHp: word;
// координаты юнита по-X
    UPosX: word;
// координаты юнита по-Y
    UPosY: word;
// новая точка перехода по-X
    UPointX: word;
// новая точка перехода по-Y
    UPointY: word;
// смещение анимации при перемещении юнита по-X
    UMoveX: shortInt;
// смещение анимации при перемещении юнита по-Y
    UMoveY: shortInt;
// знак смещения по-X
    UDispX: shortInt;
// знак смещения по-Y
    UDispY: shortInt;
// флаг пассивности
    UStay: boolean;
// флаг перемещения
    UGo: boolean;
// флаг атаки
    UAttack: boolean;
// флаг повреждения (в юнита попали)
    UDamange: boolean;
// флаг погибания
    UDie: boolean;
// флаг готовности
    UReady: boolean;
// указатель на анимацию
    UAnimIndex: word;
// тип анимации (стоит, идет, атакует, получает и пр.)
    UTypeAnim: byte;
// номер анимации (в стратегии 8 направлений, или 5 и остальные зеркальные)
    UNAnim: byte;
// текущий кадр анимации
    UKadr: byte;
// это нужно для изометрии, координата Y в два раза меденнее изменяется
    UDelay: byte;
  end;

Это далеко не все пункты, что вам могут понадобиться, но самые основные. Может что-то не указал, ...дополните.
Теперь достаточно назначить тип на наш массив и модель юнита готова:

Код:

Var
...
UnitMas: array[0..255] of TGUnit;

Теперь в основном таймере игры достаточно просматривать массив и по записи UnitMas[i].UUses (true) определять кого нужно показывать в игре.

продолжение следует...

Beermonza 21.07.2008 23:14

Про модель юнитов (продолжение)
 
продолжение...

Вот секция управления перемещением юнитов:

Код:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  for i:=0 to 255 do
    begin
      with UnitMas[i] do
        begin
          if UUses and UGo then
            begin
              if UPosX<>UPointX then
                begin
                  if UPointX>UPosX then UDispX:=1;
                  if UPointX<UPosX then UDispX:=-1;
                  if (UMoveX>{половина длины тайла}) Or (UMoveX<-{половина длины тайла}) then
                    begin
                      UMoveX:=0;
                      UPosX:=UPosX+UDispX;
                    end;
                  UMoveX:=UMoveX+UDispX;
                end
              else UMoveX:=0;
           
             
              if UPosY<>UPointY then
                begin
                  if UPointY>UPosY then UDispY:=1;
                  if UPointY<UPosY then UDispY:=-1;
                  UDelay:=UDelay+1;
                  if UDelay>1 then
                    begin
                      UDelay:=0;
                      if (UMoveY>{половина высоты тайла}) Or (UMoveY<-{половина высоты тайла}) then
                        begin
                          UMoveY:=0;
                          UPosY:=UPosY+UDispY;
                        end;
                      UMoveY:=UMoveY+UDispY;
                    end;
                end
              else UMoveY:=0;
            end;
           
          // тут обработка событий и смена анимации
          // вот так в примитиве, только смена анимации
          if UStay then UTypeAnim:=0;
          if UGo then UTypeAnim:=10;
          if UAttack then UTypeAnim:=20;
          if UDamange then UTypeAnim:=40;
          if UDie then UTypeAnim:=40;

          // смена номера кадра
          inc(UKadr);
          if UKadr>10 then UKadr:=1;

          // отрисовка (создаем свою процедуру, по всем правилам строим кадр в буфере и последней строкой выводим в форму, PaintBox или Image)
          DrawScreen;

        end;
    end;
end;

Как выглядит код отрисовки вы наверное уже в курсе из ранних неоднократных постов.
Что значит "прозрачные панели под здания" я не совсем понимаю, если мы рисуем в буфере, то достаточно иметь bmp-картинку здания, при загрузке указать прозрачность.
Вот в принципе и все, с моделью.

ИИ для стратегии


Задача достаточно сложная, готового кода у меня к сожалению нет, еще предстоит разработать только для RPG, он много сложнее. Вам же нужен примитивный. Попробую объяснить на пальцах.
Итак ИИ для стратегий. В него входит система поиска пути и система распознования целей. "Поиск пути" - достаточно распространенная тема, нас интересует самый простой частный случай - "дойти до точки назначения" (или до расстояния атаки), без особенностей, смотрим тут: http://www.delphikingdom.com/asp/vie...catalogid=1127
В системе распознования целей у нас есть цикл, он перебирает всех юнитов, берет их координаты UPosX, UPosY и прибавляет/отнимает, в соответствии, обзор UScan по всем направлениям, если на карте в этом радиусе (он не совсем радиус, скорее ромб) находится цель, то передаются координаты в систему поиска пути. В случае дальней атаки предварительно отнимается/прибавляется дистанция атаки URange.
Казалось бы это одна система, но поиск пути нам не нужен пока нет цели или пока не дана команда перейти в указанное место (мышкой).

Как интерпритировать координаты мышки в координаты карты? ...оч. просто:
Код:

  MapX:=Trunc((Mouse.CursorPos.X-Form1.Left-{поправка})/{половина длины тайла})+DispMapX;
  MapY:=Trunc((Mouse.CursorPos.Y-Form1.Top-{поправка})/{половина высоты тайла})+DispMapY;

DispMapX, DispMapY - это текущий сдвиг карты на экране, например карта 100х100 а экран где-то в центре ее и захватывает часть карты, так вот, начальные координаты экрана у нас в месте DispMapX и DispMapY.

Тут одно за другое цепляется, куча нюансов. Ну что, аркаду можно сказать сделали, теперь стратегию? :)

L_M 23.07.2008 21:41

как я понял создается массив из юнитов, потом в цикле изменяются координаты каждого согласно направлению? почему используется тип packet record, а не например просто запись, или объект?

L_M 23.07.2008 21:49

в основном меня интересует именно модель персонажа и как "приделать" к ней графику и ИИ. графику я думаю, что смогу сделать, об этом сказано достаточно, ИИ тоже несложно, но как собрать все вместе. вы уже начали объяснять как раз то, что нужно. получается надо для всего проверять весь массив(например столкновение друг с другом это цикл огромный получиться)? да и 255 это слишком мало для стратегии(если 16 рас, то по 16 юнитов получиться)-мне кажется это будет очень долго обрабатываться. я еще не знаю что делаю - рпг в стиле диабло(аллодов) или стратегию, но принцип то там будет один и тот же?

Beermonza 24.07.2008 17:40

Продолжаем разбирать модель юнитов ...
 
Цитата:

Сообщение от L_M (Сообщение 125401)
как я понял создается массив из юнитов, потом в цикле изменяются координаты каждого согласно направлению? почему используется тип packet record, а не например просто запись, или объект?

Да, ...массив динамически изменяется, ...все что содержат записи вы вольны обновлять когда вам вздумается, ...это дело игрового движка, как вы его будете писать, это ваше личное дело :)
Packet record я использую в целях экономии ресурсов, эти записи будут предварительно обработаны, и будут занимать столько памяти сколько для них требуется, в отличие от просто Record, правда чуть падает скорость, но на игре это не отразится. Применять Object вообще нет никакого смысла, никакого наследования у нас нет, строить дерево тоже не нужно, просто записи.

Цитата:

Сообщение от L_M
в основном меня интересует именно модель персонажа и как "приделать" к ней графику и ИИ. графику я думаю, что смогу сделать, об этом сказано достаточно, ИИ тоже несложно, но как собрать все вместе. вы уже начали объяснять как раз то, что нужно. получается надо для всего проверять весь массив(например столкновение друг с другом это цикл огромный получиться)? да и 255 это слишком мало для стратегии(если 16 рас, то по 16 юнитов получиться)-мне кажется это будет очень долго обрабатываться. я еще не знаю что делаю - рпг в стиле диабло(аллодов) или стратегию, но принцип то там будет один и тот же?

Все очень просто собирается "до кучи", ...в примере модели я указал UAnimIndex - указатель на анимацию, т.е. у вас уже есть массив анимации (как он создается вы в курсе), значение UAnimIndex указывает на массив анимации, на конкретную его ячейку. Этот указатель запишет ваш движок, когда создаст очередного юнита.
ИИ непосредственно управляет записями массива юнитов, обрабатывая в цикле условия.
Вспомните AOEII там лимит 200 юнитов для расы, ...у вас будет 16 массивов, причем движок будет работать только с теми, что участвуют в игре, ...как подтормаживает Империя на макс лимите все знают :) Так что вы пробуйте на малом, постепенно расширяйте.
Разница между стратегией и RPG в плане движка невелика, они часто обе содержатся в одной и той же игре, например WarCraft.

L_M 26.07.2008 22:02

вот столкнулся с такими проблемами:
при закрытии неправильно работает. в таймере обрабатывается графика, ну как в примерах, и при нажатии Esc Close; а в собственной процедуре close работает для файлов, и я не знаю как правильно завершить программу.
сразу такой вопрос где все-таки все обрабатывать? для таймера в примере был обработчик клавиатуры, а как быть с мышью?

Манжосов Денис :) 27.07.2008 13:33

Друзья, понимаю что влез не в тему вообще, но у меня вопрос. Как создать физику мяча? Сделать так точнее чтобы он мог оттталкиваться от стен, скорость остаётся постоянной.

Beermonza 27.07.2008 18:43

Цитата:

Сообщение от L_M (Сообщение 126286)
вот столкнулся с такими проблемами:
при закрытии неправильно работает. в таймере обрабатывается графика, ну как в примерах, и при нажатии Esc Close; а в собственной процедуре close работает для файлов, и я не знаю как правильно завершить программу.
сразу такой вопрос где все-таки все обрабатывать? для таймера в примере был обработчик клавиатуры, а как быть с мышью?

Прежде чем окно будет закрыто (основное окно игры), нужно остановить все таймеры, часто тут выскакивают ошибки. Все способы ссылаются на одну и туже процедуру OnClose, в ней пропишите все приготовления к завершению приложения.

Не знаю как все, а если VCL, то проще обрабатывать OnKeyDown и иже с ними OnMouse для мыши на главной форме, ...тут у вас флаги меняют свои значения по нажатию с клавиатуры или мыши, а один ОБЩИЙ таймер обрабатывает флаги, задает такт ИИ и сам же им и является, готовит графику и опять так и дает команду процедуре вывода кадра на экран.

Цитата:

Сообщение от Манжосов Денис :)
Друзья, понимаю что влез не в тему вообще, но у меня вопрос. Как создать физику мяча? Сделать так точнее чтобы он мог оттталкиваться от стен, скорость остаётся постоянной.

Такое применяется в Арканоиде, ...внимательно читайте материал, такая информация есть, и примеры тоже.

zetrix 27.07.2008 22:08

Скорость - это вектор. Реверсируем координаты вектора в зависимости от стены, от которой отталкиваемся. От вертикальных - реверс Х, от горизонтальных - реверс Y.

L_M 01.08.2008 22:05

у меня возникла такая проблема: как заставить юнита идти в нужную точку? ну с прямой это просто и понятно:
Код:

while (man.x<>click_x)and(man.y<>click_y) do begin
    man.x:=man.x+speedx;
    man.y:=man.y+speedy;
end;

а вот как сделать движение по карте? если клетка по размеру гораздо больше игрока? ну то есть объясните, как сделать переход просто в соседнюю клетку(без диагоналей).

Beermonza 03.08.2008 00:10

Возвращаясь к напечатанному...
 
Возвращаемся к посту #155, еще раз разбираем код:

Код:

procedure TForm1.Timer1Timer(Sender: TObject); 
 begin 
  for i:=0 to 255 do  // количество юнитов 256
    begin 
      with UnitMas[i] do  // работаем с массивом
        begin 
          if UUses and UGo then  // если юнит используется и он может перемещаться
            begin 
              if UPosX<>UPointX then // если его текущая позиция на карте по-X не равна той которая указана (куда он должен перейти)
                begin 
                  if UPointX>UPosX then UDispX:=1;  // если новая позиция правее, то будем прибавлять координате 1
                  if UPointX<UPosX then UDispX:=-1; // если новая позиция левее, то будем отнимать 1 (прибавлять минус единицу) 
                  if (UMoveX>{половина длины тайла}) Or (UMoveX<-{половина длины тайла}) then  // вот тут у нас размеры одной клетки всплывают,
// задаем половину и юнит будет топать столько пикселей, сколько нужно до перехода на следующий тайл (клетку карты).
                    begin
                      //  по завершению перехода текущая позиция меняется
                      // смещение обнюляется
                      UMoveX:=0; 
                      UPosX:=UPosX+UDispX; 
                    end;
                  // тут мы "двигаем" юнита на один пиксел в нужном направлении 
                  UMoveX:=UMoveX+UDispX; 
                end 
              else UMoveX:=0; 
             
// по оси Y аналогично, только лишь через UDelay смещаем во времени сдвиг ровно в два раза относительно X               
              if UPosY<>UPointY then 
                begin 
                  if UPointY>UPosY then UDispY:=1; 
                  if UPointY<UPosY then UDispY:=-1; 
                  UDelay:=UDelay+1;  // вот сдвиг
                  if UDelay>1 then 
                    begin 
                      UDelay:=0; 
                      if (UMoveY>{половина высоты тайла}) Or (UMoveY<-{половина высоты тайла}) then 
                        begin 
                          UMoveY:=0; 
                          UPosY:=UPosY+UDispY; 
                        end; 
                      UMoveY:=UMoveY+UDispY; 
                    end; 
                end 
              else UMoveY:=0; 
            end;


          ...



        end; 
    end; 
 end;

Если вы создали модель уровня (карту) и модель юнита, создали одну запись в массиве - включили юнита, то по процедуре описанной в посте #155 юнит идет в любую точку карты, которую вы задали при помощи мышки, через формулу интерпритации координат мыши в координаты карты, причем, направление перемещения юнит меняет сам.

Titan123 05.08.2008 14:56

пожалуйста, напишите урок по создании крестиков-ноликов. хотя бы простейших 3*3
разбираю исходники, не понимаю кода!

AlDelta 05.08.2008 17:06

Titan123, а что именно непонятно? Давайте первый непонятный кусок кода.

mutabor 05.08.2008 21:03

Titan123, тебе нужно поучиться алгоритмы составлять. Не обязательно на играх, любые задачки подойдут. Есть книжки такие с задачками и с их алгоритмами, например "200 задач на С/С++", может для Дельфи такие есть, но язык не важен, также как и среда, хоть в КьюБейсике, главное - алгоритмы.
Иначе у тебя будут постоянно подобные вопросы.

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

Урок писать это долго, лучше приведи непонятный кусок кода (переменные не потеряй только). Хотя если на работе завтра нечем будет заняться, напишу крестики нолики 3х3 (никогда раньше не делал и код не видел, интересно что получится).

L_M 05.08.2008 23:16

Вложений: 1
Народ, помогите мне пожалуйста. У меня неправильно ищется маршрут - приходит в другое место перс. И еще просьба: напишите еще несколько уроков по играм, например про оптимизацию, хранение различных ресурсов.
Вот что у меня пока получается:

mutabor 06.08.2008 00:09

L_M, уже обсуждали, причем привели несколько вариантов.
http://www.programmersforum.ru/showt...3612#post53612

Kostia 06.08.2008 10:13

Насчет оптимизации. Это очень обширная тема про которую можно не один том написать. Советую начать с изучения архитектуры компьютера. Когда знаешь как работает твое железо, то можно и оптимальную для него программу написать.
Хранение различных ресурсов - это уже не раз обсуждалось, поиск по форуму или Google.

Titan123 06.08.2008 15:11

Вложений: 1
я писал крестики-нолики, составил несколько десятков комбинаций противника, кода получилось очень много, рассматривая другой исходник К-Н я понимал, что делаю неправильно.
у меня все банально: например,
Код:

if  (panel1.caption='0') and (panel5.Caption='0') and  (panel9.Caption<>'x') then begin panel9.caption:='0'; end
else begin
if  (panel9.caption='0') and (panel5.Caption='0') and  (panel1.Caption<>'x') then begin panel1.caption:='0'; end
.........

panel и-это и есть игровое поле.
но это все неверно.

выкладываю не мои К-Н, может, вы объясните мне о чем там говориться.

Beermonza 06.08.2008 19:19

To L_M

Мде, я немного затерялся в вашем коде. При разработке игры создайте дополнительно панельку (Panel), в которую поместите лэйблы (Label), напишите процедуру сбора данных, это вам поможет видеть текущие значения переменных и тем самым ошибки работы программы. Обязательно текущие координаты мыши, клетки карты, позиция персонажа, и дополнительные на тип действия или еще что.

Я предложил простейший пример движения персонажа, мне кажется он самый простой в понимании и реализации, ...вот так он выглядит на практике:

0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 Т 0 0 0 0 0
0 0 0 0 0 0 0 0 | 0 0 0 0 0
0 0 0 0 0 0 0 0 | 0 0 0 0 0
0 0 0 0 0 0 0 / 0 0 0 0 0 0
0 0 0 0 0 0 / 0 0 0 0 0 0 0
0 0 0 0 0 / 0 0 0 0 0 0 0 0
0 0 0 0 П 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0


П - текущие координаты персонажа
Т - точка, куда нужно переместиться

Логика

Зная координаты персонажа и новой точки нужно сравнивать поочереди X и Y.

Код:

if UPointX>UPosX then UDispX:=1;
if UPointX<UPosX then UDispX:=-1;
...
if UPointY>UPosY then UDispY:=1;   
if UPointY<UPosY then UDispY:=-1;

Теперь остается только каждый такт прибавлять найденные сдвиги, пока каждая из координат персонажа не станет равной координатом указанной точки:

Код:

if UPosX<>UPointX then
  begin
    UPosX:=UPosX+UDispX;
  end;
...
if UPosY<>UPointY then
  begin
    UPosY:=UPosY+UDispY;
  end;

Это самый грубый вариант, перемещение сразу на клетку, ...а как сгладить вы уже видели выше :)
Настоятельно рекомендую попробовать :cool:

mutabor 06.08.2008 22:31

To Titan123, дам совет. Разделяй код логики и вывода на экран. То есть обработка геймплея не должна базироваться на панелях или на кнопках или на чем-то там еще. Делай универсальный (абстрактный, не зависимый от графики) код, к к-рому можно будет прикрутить любой вывод на экран. Читабельность кода намного вырастет, да и не всегда у тебя будут панели чтобы на них опираться.
Используй структуры, классы, просто переменные, массивы и т.д.

Крестики нолики не делал, времени нет. Но подумал, как бы я их сделал. Сразу отбросил вариант 3х3, слишком маленькие, алгоритм даже потестировать негде, тесновато и не интересно. Я еще с первого класса помню какой нужно сделать первый ход чтобы выиграть.
Я бы сделал поле 10х10, и по таким правилам, если пять подряд по горизонтали, вертикали или диагонали выстроил - победа. Не совсем крестики нолики но так интересней.
Думал над алгоритмом. Сразу нужно отсеять рутинные операции типа вывода на экран, очистки поля, обработки мыши и т.п. В итоге я бы сделал функцию "СделатьХод"

MakeMove(параметры): возвращаемый тип;

Вобщем она должна сделать ход, параметры и возвращаемое значение можно сделать разные, но на вход она должна получить игрока за к-рого ходить, т.е. крестиком или ноликом, уровень мастерства, т.е. насколько умным должен быть ход (Random - самый тупой =), а вернуть позицию куда лепить тот же крестик или нолик. Матрицу - игровое поле можно передать в параметрах или обращаться к ней как к глобальной.
С теорией пока все, сделать так чтоб работало не проблема, но все что приходило мне в голову какое-то громоздкое и слишком "человеко ориентированное". Тут наверное математика не помешала бы.

mutabor 06.08.2008 23:07

Посмотрел те крестики нолики, ну и наворочено. Явно для примера не подходят, процедура где генерируется следующий ход - procedure putO(); в Unit1, вся суть в ней.
Игровое поле матрица 3х3 of integer;
Как такового алгоритма нет, тупо проверяются различные комбинации, заточено под поле 3х3, если бы таким методом сделать проверку поля 10х10, код вырос бы до огромных размеров.
Там где компьютер - дурачок, ход генерируется функцией Random.
Там где поумней - 200 строк кода, сплошные проверки if. Наверное перебрана каждая комбинация к-рая может возникнуть на поле.

Beermonza 07.08.2008 14:35

mutabor, простого показательного кода не получить в любом случае. Тут как в шахматах, есть логические ходы, БД с комбинациями, проверка в ней на соответствие, это первое, ...а второе - перебор последовательности вероятного хода противника до оптимального варианта, в котором будет выигрыш за какое-то число ходов.
Так что, 3х3 хоть и не интересно, но показательно с точки зрения алгоритма.

Beermonza 07.08.2008 17:17

Простой пример основы РПГ
 
Вложений: 1
Вот, держите примерчик. Упрощено до минимума, на исходниках L_M.
Это может быть РПГ или стратегия.

L_M 08.08.2008 21:23

спасибо, то что нужно было...пока.

mutabor 09.08.2008 00:40

Урок Крестики-нолики на большом поле Часть1
 
Вложений: 1
В этом уроке я расскажу как сделать большие крестики-нолики на Дельфи. Скорее всего вы знаете эту игру, возможно под другим названием. Объясню вкратце: прямоугольное поле в клетку, кто раньше выстроил пять своих фишек (крестиков, ноликов, клякс и т.п.) подряд по горизонтали, вертикали или диагонали тот и выиграл.

Урок расчитан на новичков, если вы не новичек, для вас тоже может найтись интересное, почитайте P.S.

Итак приступим.

Часть первая — интерфейс.

Для вывода графики будем использовать компонент TImage. Поле будет 10х10 клеток, но код будет универсальный и вы потом сможете без особого труда сделать изменяемые размеры. Поле реализовано как двумерный массив с элементом типа Shortint, вместо него можно было и Integer использовать, Shortint выбран т.к. занимает меньше памяти. Тип выбран с возможность присваивать отрицательные значения, -1 будет означать пусто, 0 — нолик, 1- крестик.
Можно было создать свой перечисляемый тип для элемента, со значениями Krestik, Nolik, но простые числа более гибкие в коде, с ними удобнее, хотя не так наглядно.

Рассмотрим секцию var

Код:

var
  Form1: TForm1;
  CPUSkill: byte; //мастерство компьютера
  CPUMark: byte; //чем играет компьютер
  HumanMark: byte; //чем играет человек
  table: array of array of shortint;
  TableWidth: byte = 10;
  TableHeight: byte = 10;

CPUSkill — уровень мастерства компьютера, их может быть много, я сделаю два, новичек и мастер.
CPUMark, HumanMark — будет хранить кто чем играет, крестиком или ноликом. 0 — нолик, 1 — крестик. В дальнейшем я буду стараться чтобы 0 совпадал с ноликом при создании переменных.
table — игровое поле.
TableWidth, TableHeight — тут думаю понятно ширина и высота. Менять не советую, так как в процессе написания универсльность несколько потерялась.

Константа одна - CELL_SIDE = 40; это размер клетки, а точнее длина ее стороны в пикселях.
TImage соответственно будет иметь размеры 400 х 400.
Настройки я засунул в главное меню, их там немного и вы сами я думаю разберетесь. Выбор противника не работает, но в коде все под него есть, алгоритмы заточены ходить за любого игрока. Так что доделать будет не так сложно, лучше выбор игроков сделать в двух комбобоксах, чтобы разные алгоритмы друг на друге тестировать можно было.

Смотрим дальше главный юнит — Main. (Код во вложении.) Сначала идут обработчики пунктов меню, в них ничего интересного. Дальше идет сам игровой процесс. Он состоит из двух процедур — обработчик нажатия мыши в Image и обработчик пукта меню Новая игра.
Вот и вся игра. Но это конечно не весь код, самое интересное скрыто в юните Game, о нем попозже.

mutabor 09.08.2008 00:41

продолжение...
 
В обработчике пункта Новая игра всего одна строка - вызов функции NewGame;
В ней описаны все действия необходимые при старте новой игры. Какие в этот момент выбраны настройки в меню, с такими и начнется игра.

В процедуре Image1MouseDown заключается высокоуровневый алгоритм игры, как видите он довольно простой, если не вникать в сами функции. Разберем по строкам.

cx:=x div CELL_SIDE;
cy:=y div CELL_SIDE;
Переводим координаты клика из пикселей в координаты клетки на поле.

if Empty(table[cx,cy]) then
Функция Empty возвращает True если клетка пустая, т.е. в нее можно ходить

HumanMove(cx,cy);
Ходим.

Application.ProcessMessages;
Это нужно чтобы ваш ход сразу отобразился на экране. Иначе это произойдет только после завершения всей процедуры.

if EndOfGame = 0 then
Проверяем не выиграли ли мы. Или не последний ли это был возможный ход. Функция EndOfGame вернет 0 — если еще не конец игры, 1 - выиграли нолики, 2 — крестики.

Sleep(500);
Если управление дошло сюда, значит еще не конец игры. Делаем задержку в полсекунды, чтобы компьютер не отвечал мгновенно.

CPUMove(CPUSkill,CPUMark);
Ходит компьютер. Параметры — уровень мастерства и чем собственно ходить.

if EndOfGame > 0 then ShowMessage('the end '+IntToStr(EndOfGame));
Если условие верно, значит наступил конец игры после хода компьютера. Результат игры возвращает та же функция, об этом написано выше. ShowMessage здесь просто как заглушка, к написанию второй части урока я это доделаю.

else ShowMessage('the end '+IntToStr(EndOfGame));
То же самое, только конец игры наступил после хода человека.

Пока это все. Разбор юнита Game будет во второй части урока.
В текущей версии при выборе мастерства Новичек и Мастер, компьютер ходит всегда как новичек, вообще не думая, используется Random. Над более продвинутым алгоритмом я как раз сейчас думаю.

P.S. Для кое-чего умеющих. Если вам интересно, можете написать свою версию алгоритма для хода компьютера - procedure CPUMove(skill: byte; mark: byte);
На вход процедура получает уровень мастерства и чем ходить. Доступ к массиву как к глобальному. Массив 10 х 10 -
table: array of array of shortint;
//-1 — пусто, 0 — нолик, 1 — крестик
Готовый ход делается в конце процедуры двумя строками
table[x,y]:=mark; //сохранение хода в матрице
PutMark(x,y,mark); //вывод хода на экран
Для отладки можете использовать проект во вложении, он рабочий.

Titan123 12.08.2008 13:42

mutabor спасибо, что откликнулись на мою просьбу, но компьютер играет довольно скудно.
я, конечно, буду разбираться в коде, но как можно увеличить его мастерство?

DeKot 12.08.2008 18:14

Всем привет!Первый раз на этом форуме.Очень жалею, что только сейчас обнаружил этот форум. Давно занимаюсь изучением программирования и мне кажется ,что через создание игр, даже простейших, самый оптимальный способ обучения.Создал несколько игрушек, но есть вопросы.Вот только незнаю куда и как можно выложить коды,exe-шники,
чтобы потом давать на них ссылки.Подскажите, плз.

Rembo 12.08.2008 19:11

Цитата:

Сообщение от DeKot (Сообщение 130891)
Вот только незнаю куда и как можно выложить коды,exe-шники,
чтобы потом давать на них ссылки.Подскажите, плз.

Код программы можно выкладывать и в самом сообщении, но при этом не забывать использовать тег [code]. exe-шники можно выложить в виде архива во "вложении" или же если файл большой (не помещается во вложение), можно использовать файлообменники например этот или этот. И после загрузки файла на файлообменник, просто выложить ссылку на скачивание вашего файла...

mutabor 12.08.2008 19:38

Цитата:

Сообщение от Titan123 (Сообщение 130799)
mutabor спасибо, что откликнулись на мою просьбу, но компьютер играет довольно скудно.
я, конечно, буду разбираться в коде, но как можно увеличить его мастерство?

Он вообще не играет. Это пока оболочка, интерфейс игры. А ходит он случайным образом. Я думал над алгоритмом, во второй части урока будет описание его, и вообще модуля Game. Все руки не доходят дописать, постараюсь на днях написать.

DeKot 13.08.2008 15:47

Еще о движениях персонажей
 
Вложений: 1
Простенький пример передвижения для новичков в 2D.Принцип - покадрового вывода из файлов (можно из файла ресурсов или из Image
List, что предпочтительнее для .exe файлов) с последующим затиранием
фоном и сдвигом вывода след. кадра.Винни скопирован здесь же на форуме (прошу прощения).
Запустите программку и нажмите "стрелка влево"(можно держать непрерывно.Это только принцип движения. который можно видоизменять под свои нужды.

Titan123 14.08.2008 14:33

Вложений: 1
mutabor я, в помощь, выложу не мои большие К-Н. я в коде ни чего не понял, но компьютер играет довольно хорошо. может, вам это поможет в написании алгоритма

L_M 14.08.2008 22:14

Вложений: 2
Вот двое моих крестиков-ноликов. алгоритм хода компьютера очень прост: он считает для каждой клетки сколько будет рядом таких же, т.е. сколько рядом, если туда поставит компьютер минус сколько будет при ходе игрока.

mutabor 15.08.2008 10:21

Цитата:

Сообщение от Titan123 (Сообщение 131347)
mutabor я, в помощь, выложу не мои большие К-Н. я в коде ни чего не понял, но компьютер играет довольно хорошо. может, вам это поможет в написании алгоритма

Проблема не в написании алгоритма, у меня элементарно нет пока на это времени. Смотреть специально пока не буду, хочу свой велосипед написать, потом сравню. Если тот окажется лучше, возможно, если разберусь в нем, напишу урок на его основе.
Пока доработал программу, заточил под использование разных алгоритмов, в ней и сравню. Если конечно получится чужие алгоритмы под свои условия игры подогнать.

Скриншот >>>

Beermonza 18.08.2008 19:58

Предотвращение ошибок
 
Частенько на форуме мы слышим "программа выдает ошибку...", ...свой собственный код, оказывается не под силу отладить самостоятельно, или же код не работает на сторонних ПК по непонятным причинам. Стандартное сообщение с ошибкой адреса абсолютно ни о чем не говорит пользователю.
Есть замечательная структура Try..Except..End. Неуверенный в своем коде программист может вплоть до каждой строки заключить в эту структуру и при том сторонние пользователи его труда будут знать где программа работает некорректно, и что нужно делать, разумеется если автор постарается с классификацией ошибок.
Вот так может выглядеть часть кода:

Код:

...
try
  begin
    // несколько строк кода
  end;
except
  // вызов стандартного окна сообщения
  // или какая-либо процедура записи в файл, ...в общем что угодно
end;
...

Очень удобно использовать данный способ с Log-файлом, в котором будут отмечаться все ошибки работы программы, что собственно мы и видим в большинстве нормально разработанных программ.

BangBangFM 23.09.2008 17:57

Всем привет! Вот увидел темку и решил поучаствовать. Написал урок про то что меня волнует больше всего - скрипты в играх. Вобщем вот:
http://webfile.ru/2253596

Beermonza 23.09.2008 18:46

Большая просьба, ...оформите пожалуйста в виде урока, разбейте на части, ...а в прикрепленном файле оставьте архив проекта.

[Smarik] 02.10.2008 19:55

Добрый вечер, решил делать следующую игру для телефона, но уже серьезную, аналог гта 2, только без машин, решил все делать хорошо и реалистично, например бег по траве ниже чем по асфальту, решио делать землю из квадратов содержащиеся в массиве, так и графику легче загружать, только такой вопрос, как например a[1]:=квадрат 10 на 10? я могу по 1 пикселю присвоить, но не больше...еще если там будет содержаться етот квадрат...а я хочу еще помечать что если a[1]=1 то ето вода =2 ето земля =3 песок =4 трава и.т.д...массив занят как тогда реализовать такое?
Так....далее, карту я планирую делать примерно в 30 дисплеев телефона, тобишь огромная территория, как мне устанавливать здания? так и писать координаты x=-1200 y=-300, x=3000, y=-1300?

Beermonza 03.10.2008 14:46

[Smarik], в посте #154 "Про модель юнитов" описан принцип хранения объектов, будь то строения, юниты (персонажи), или даже текстуры. У вас будет массив особого типа, в котором записи нужных типов, в которые вы запишете все нужные вам параметры, включая графику.

[Smarik] 19.10.2008 21:13

Разрешите влесть не в тему, в прошлый раз меня послали в 154 пост, но мне показалась, там не совсем то, чего я желаю, есть частица истины, но реализована не для моих целей.
Мне нужна земля, по типу шахматной доски, тоесть квадратами, чтобы если я укажу drawimage(image,5,12) он четко покажет картину в нужный квадрат, я додумался только до варианта:
Код:

drawimage(image,x,y);
drawimage(image,x+30,y);
drawimage(image,x+60,y);
и.т.д

через цикл все терпимо, но ведь кривовато, получается что drawimage(image,x,y) ето левая верхняя точка квадрата рисунка, уже неудобно обрабатывать столкновения и сканировать местность...

Beermonza 21.10.2008 17:01

[Smarik], т.е. у вас отображение участка карты идет как экран - локация? ...она статична, и не двигается, а в ней много объектов?

[Smarik] 21.10.2008 17:16

да статична, объектов пока что будет мало, трава, вода, огонь, каждой свою клетку, далее будут дома, заборы..ну много всего, вроде как сути не имеет, мне говорили что в героях примерно такой же алгоритм и что его возможно найти, но гугл мне не помог, использовал десятки запросов.

Beermonza 21.10.2008 20:56

Про локации...
 
Именно по этому и отправил вас читать 154-й пост. Не имеет значения как вы позиционируетесь на карте, важно то, как вы представляете данные карты в памяти ПК, в вашем случае СТ (сотового телефона).
Представьте себе лист в клеточку - это локация, в каждой клетке у нас может быть записано множество разнотипных данных. А теперь представьте что к этому листу в клеточку, вы положите справа еще такой же лист, ...что будет? у вас будет еще одна локация, у первой номер 1, а у второй - 2. Теперь вам нужно создать массив числового типа с индексами этих локаций, каждая из которых - тоже массив нужного размера, но уже особого типа, для записи картинок и пр. данных для каждой ячейки.
Чтобы отрисовать нужную локацию, вам нужно знать ее номер, а позиционирование в ней будет от ее верхнего левого угла, т.е. от X = 0, Y = 0.

Алкаш 28.10.2008 19:14

возможно я повторюсь, но как лучше игру создавать:
чтобы объекты TShape(как написано на 1-ой странице) и др. двигались по форме или одни картинки TBitmap(какие можно ещё?) по объекту TImage(посоветуйте какой объект в данном случае использовать удобнее)
---
в моих играх на Delphi6 всё прорисововалось на объекте DXDraw модуля DelphiX.
это что-то вроде канвы, но удобнее (до сих пор не разобрался во всех прелестях)

Beermonza 28.10.2008 20:19

Для начала, прочитай всю тему "Уроки по созданию игр для новичков", попытайся повторить предложенные алгоритмы, только не просто скопировать, а осмыслить что и зачем, можно поиграться с переменными, определить что за что отвечает в коде. Одним словом, прежде чем создавать игру нужно сносно знать Delphi, уметь оперировать командами, знать элементарные приемы программинга и тд. и тп. и третье и десятое.

apromix 30.11.2008 11:04

Оформи для меня какую-то маленькую часть проекта в задачку для нескольких функций, сначала что-то попроще, что вводить и что нужно получить на выходе. Вышли на bees[]meta.ua. Заделаю на досуге, времени сейчас появилось море, хочу поучаствовать в твоем прожекте :)

challengerr 26.12.2008 13:44

Хочу создать что-то типа стратегии Heroes 3. На GDI я смог бы без проблем создать, но нужно DirectX.
Не понимаю, как использовать DirectX для отображения карты. Способ хранения будет матрицей. Мне непонятнj, как отрисовывать карту с помощью DirectX на поверхности.
Вопрос здесь http://www.programmersforum.ru/showthread.php?t=34393
Нужно делать какое-то матричное преобразование?

Lemo 05.01.2009 20:32

Ребята, тема действительно интересная и очень полезная! Но было бы действительно классно, если бы все велося как на 1 страничке, код, и коментарии к нему, как это делал автор Темы!а сейчас просто свободный флуб профессионалов, общающихся между собой, может где то на форуме есть что то подобное, как 1 страница! А не вышеуказаный флуД?! Вот я лично полный новичек, и вы вкладываете уже готовые игры, я не могу понять как и что! Тема же называеться "Уроки..."!

DM_bite 05.01.2009 21:32

если ты новичок, то качай исходники и разбирайся с ними, а что не получиться - пиши, поможем... а с налету ничего не бывает ;-)

Lemo 05.01.2009 22:05

я за то, что бы детально обьяснялся материал, как на 1 странице!

Манжосов Денис :) 07.01.2009 16:45

А нет ли более удачного алгоритма проверки сталкивания предметов с персонажем чем этот.
Код:

var Player: TPoint;
    Objects : array [1..16] of TPoint;
..
// Объекты уже расставлены
..
 for i:=1 to High(Objects) do
  begin
  if (Player.X >= Objects[i].X) or (PLayer.X <= Objects[i].X)
      or (PLayer.Y >= Objects[i].Y) or (Player.Y <= Objects[i].Y) then
  begin
  PLayer.X := PLayer.X;
  PLayer.Y := Player.Y;
  Break;
  end;
  end;

Проверка идёт в таймере, когда игрок двигается, а если объектов 1000?

Beermonza 07.01.2009 17:10

Если объектов 1000 одновременно, то так тому и быть, ...например игровой сервер ворочиет их всех вместе по порядку или в потоках, ...все равно нужно всех проверять.

Лубышев 19.01.2009 04:28

Нахождение оптимального маршрута и обхождение препятствий
 
Допустим есть карта-двумерный массив из проходимых и не проходимых зон. Персонажу нужно попасть из точки А в В проходя только через проходимые ячейки. при чем этот маршрут должен быть самым коротким. Кто нибудь знает как быть? Нужен алгоритм или код на дельфи с объяснением. ну или хотя бы посоветуйте как быть

Dj_smart 19.01.2009 10:42

Читаем про так званый "алгоритм дейкстры" :)
http://www.google.ru/search?hl=ru&q=...80%D0%B8%D1%82

Beermonza 19.01.2009 17:07

Лубышев, вот тут интересная статья с примером http://www.delphikingdom.com/asp/vie...catalogid=1127

Oberon_92 19.01.2009 18:10

Прива всем. Токо что сюда попал. Народ, подскажите, с помощью какой програмы можно делать игры, ну пока 2D естествено?

Beermonza 19.01.2009 23:48

Делают игры с помошью движков готовых, а сей форум в основном посвящен среде программирования - Delphi, а тема эта для тех, кто будет писать код для своей игры на Delphi, и не знает с чего начать, или знает, но есть вопросы.

Arigato 20.01.2009 11:22

Цитата:

Сообщение от Лубышев (Сообщение 188855)
Допустим есть карта-двумерный массив из проходимых и не проходимых зон. Персонажу нужно попасть из точки А в В проходя только через проходимые ячейки. при чем этот маршрут должен быть самым коротким. Кто нибудь знает как быть? Нужен алгоритм или код на дельфи с объяснением. ну или хотя бы посоветуйте как быть

Посмотрите тут:
http://www.programmersforum.ru/showthread.php?t=10952#6
Я приводил исходник поиска оптимального пути в лабиринте.

Лубышев 22.01.2009 21:43

Ну все... персонажи бегают по карте и дерутся между собой в ближнем бою. теперь такой вопрос. как быть с дальнем боем? Кто нибудь знает где взять учебный материал для создания на канвасе таких эффектов как фаербол или летящая из одной точки в другую молния и т. п. ? Пытался с помощью примитивов нарисовать по формуле но что то не очень правдоподобно получается.

Arigato 23.01.2009 13:49

Лубышев, можно использовать что-то типа спрайтов. Делать игрушки на канве не совсем эффективно. Но если уж взялись, можно TImageList использовать.

Beermonza 23.01.2009 16:01

Цитата:

Сообщение от Arigato (Сообщение 191601)
Лубышев, можно использовать что-то типа спрайтов. Делать игрушки на канве не совсем эффективно. Но если уж взялись, можно TImageList использовать.

Или без него, просто массив типа TBitmap, ...длина массива - количество кадров анимации эффекта. А если двумерный массив, то столбцы - тип анимации или тип эффекта.

Лубышев 26.01.2009 13:10

То есть нужно чтобы эффекты были нарисованными? т. е. не нужно их рисовать программно? ну тогда вот например как сделать молнию бьющию из одной точки в другую если мы не знаем ни длинны ни направления изначально. это зависит от координат где находятся противники. Под это уже не нарисуешь картинку. это нужно вырисовывать программно

Beermonza 26.01.2009 14:41

Цитата:

Сообщение от Лубышев (Сообщение 193338)
То есть нужно чтобы эффекты были нарисованными? т. е. не нужно их рисовать программно? ну тогда вот например как сделать молнию бьющию из одной точки в другую если мы не знаем ни длинны ни направления изначально. это зависит от координат где находятся противники. Под это уже не нарисуешь картинку. это нужно вырисовывать программно

Неужели? ...давай подумаем. Если взять длинный размер анимации, молния бет с самого верха экрана в самую нижнюю точку, и если использовать ее для центра, достаточно сдвинуть ее начало за пределы, а точнее ориентировать по длине от начала экрана до точки удара, то простой обрезкой можно наложить анимацию молнии куда-угодно. Кушать это все дело будет в разы меньше, чем рисовать программно, и тем более у тебя всегда будет возможность подправить анимацию не вмешиваясь в код программы.

Лубышев 26.01.2009 16:40

С размером понятно. А вот с направлением не очень. Нужны изображения во всех направлениях-? то есть иметь пачку картинок с молнией с отклонением как в веере на 15 допустим градусов-? А применять ту или иную картинку в зависимости от угла между осью и вектором удара-?

Beermonza 26.01.2009 17:23

Обычно молния бъет с неба на землю, все остальное - уже не молния, это типа огненные/ледяные/иные болты, энергетические стрелы и пр. плазма. Есть еще способ, нужно сделать анимацию некоторого среза молнии, потом передвигать эту анимацию от точки до точки причем не стирая предыдущие наложения. Тут нужно видение этого среза, можно по началу с примитивом, освещение в Фотошопе.

Манжосов Денис :) 31.01.2009 18:09

Игра как пример
 
Вложений: 1
Урок XXX
Тема: Игра
Описание: Маленькая игра, в которой вы бегаете от человечка. Правила просты - продержаться до 6 уровня. Предоставляется открытый исходный код. Игра как пример работы с Bitmap и не только. В-общем, новичкам, я думаю, будет полезно.

Stanislav 03.02.2009 00:38

Вложений: 1
Цитата:

Сообщение от Kostia (Сообщение 116592)
Меня небыло 2 недели, а тут почти ни каких продвижений в Gamedev'е.
L_M, пока плоховато.
У меня после пары запусков, все иконки с рабочего пропали, это может быть вызвано, не правильной очисткой памяти или ее не очисткой. При выходе вылетает ошибка, пока еще не разбирал код, но мне кажется что ты чего не создал, а потом пытаешься его использовать или освободить его память. Пока с освобождение памяти можешь не мучаться, все за тебя delphi сделает.

Меня затянул мой предыдущий пример и я захотел улучшить его, гляньте что получилось. Разрешение 320*240, fullscreen. Когда запустил игру в таком режиме, я снова вспомнил когда мне было 6 лет и денди к черно-белому телеку подключенный. Короче прикольная игрушка, от которой веет стариной, получилась.

Управление: Left, Right, up или space.
Цель: собрать зелененькие шарики и добраться до двери.
Описание: вы играете маленьким шариком. Вам нужно пройти лабиринт с ловушками и собрать зеленые шарики и пройти на следующий уровень через дверь. В лабиринте вам встретятся разные ловушки: электрические ловушки, шипы и батуты которые не всегда будут вам помогать.


А скажите если вас не затруднит как то же самое но под разрешение 1024 на 768, я пытался сделать следующее:



Код:

function SetFullscreenMode:Boolean;
var
  DeviceMode : TDevMode;
begin
  with DeviceMode do
  begin
    dmSize:=SizeOf(DeviceMode);
    dmBitsPerPel:=32;
    dmPelsWidth:=1024;
    dmPelsHeight:=768;
    dmFields:=DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT;
    result:=False;
    if ChangeDisplaySettings(DeviceMode,CDS_TEST or CDS_FULLSCREEN) <> DISP_CHANGE_SUCCESSFUL
    then Exit;
    Result:=ChangeDisplaySettings(DeviceMode,CDS_FULLSCREEN) = DISP_CHANGE_SUCCESSFUL;
  end;
end;

Код:

//настроим параметры буфера
  mapbmp:=TBitmap.Create;
  mapbmp.Width:=1024;
  mapbmp.Height:=768;
  mapbmp.Canvas.Brush.Style:=bsClear;
  mapbmp.Canvas.Font.Size:=10;
  mapbmp.Canvas.Font.Style:=[fsBold];
  mapbmp.Canvas.Font.Color:=clWhite;


Создал карту размером 64 на 48 я так понимаю умножив эти значения на 16 получим 1024 на 768.

И еще пробижался по коду и заменил где было 320 на 1024 и 240 на 768 однако саму игру отображает мелким размером а все остальное пространство белое..

Получается собственно что то похожее на это:

Beermonza 03.02.2009 15:20

Мне кажется нужно изменить размеры спрайтов, и кроме того, изменить пропорции отображения, там где умножается на коэффициент 16, если не ошибаюсь, поиграйся с ними, а еще лучше в место числа впиши переменную, меняя ее в одном месте везде будет правильный сдвиг.

Oberon_92 05.02.2009 17:21

С помощю какой програмы всё это делать? И где её можно скачать?
скаиньте ответ мне в почтовый ящик пожалуйста.

NaoMao 21.02.2009 21:04

Всем привет, у меня такая проблемма-->
Надо реализовать задержку при выполнении части процедуры, но так чтоб она не мешала производить другие манипуляции в программе.. напримере:

procedure Primer(A,B:TClass; Memo:TMemo);
begin
Memo.Lines.Add(ShowMes(A.n,1));
sleep(800);
while ((A.i>0) or (B.i>0)) do
begin
Memo.Lines.Add(ShowMes(A.n,2));
sleep(800);
Memo.Lines.Add(ShowMes(A.n,3));
sleep(800);
end;
end;

листинг процедупры находится в отдельном unit'е
и вызывается таким образом:

procedure TForm1.Button1Click();
var
At,Bt:TClass;
begin
Primer(At,Bt,Form1.Memo1);
end;

Вобщем вместо Sleep(800), что можно придумать, чтоб оно не мешало работе с программой?

Манжосов Денис :) 21.02.2009 21:26

Можно попробовать втсавить Application.ProcessMessage в тело цикла, но это мало поможет.

Beermonza 22.02.2009 16:13

Цитата:

Сообщение от NaoMao (Сообщение 209249)
... Вобщем вместо Sleep(800), что можно придумать, чтоб оно не мешало работе с программой?

Паузы почти секундные, по силам выполнить через Timer.

Лубышев 24.02.2009 08:18

Игра на Canwas. Если игровой мир очень большей, то это дело будет не реально как-то загрузить. На загрузку карты в несколько то экранов уйдет много ресурсов. вот я думаю можно ли как то грузить только то, что находится в ближайшей видимости?
И еще если персонажей очень очень много в мире, то нужно обробатывать их всех на взаимодействие. Как можно сделать, чтобы проверялись на взаимодействие только те, которые находятся не очень далеко?

Kostia 24.02.2009 10:11

Цитата:

гра на Canwas. Если игровой мир очень большей, то это дело будет не реально как-то загрузить. На загрузку карты в несколько то экранов уйдет много ресурсов. вот я думаю можно ли как то грузить только то, что находится в ближайшей видимости?
Все это дело можно провернуть так, как сделала Bethesda в своих играх(Morrowind, Oblivion). Они разбили всю карту на небольшие куски и грузятся только те которые находятся рядом. Когда игрок выходит за пределы какого либо куска, то одни ресурсы высвобождаются, а на их место загружаются новые.
Цитата:

И еще если персонажей очень очень много в мире, то нужно обробатывать их всех на взаимодействие. Как можно сделать, чтобы проверялись на взаимодействие только те, которые находятся не очень далеко?
Проверяй только тех, кто находится в том куске где находится герой.

00000000
00011100
00012100
00011100
00000000
0 - не загруженый участок карты
1 - находится в памяти
2 - участок в котором находится гг.
Можно сделать, чтобы куски грузились в отдельном потоке, тогда можно избежать тормозов при переходе. Хорош для игр от первого лица, если добавить туман, который не позволит увидеть дальше загруженой области.

0000
0100
0000

Если в памяти держать всего один кусок, то придется ждать, пока загрузится следующий кусок, хоть в отдельном потоке, хоть прямо в игре. Но потребление ресурсов снизится. И этот вариант хорошо должен подойти для игр с видом сверху.

Еще можно применить частичную загрузку всей карты. Определить на каждом участки карты расстояние до гг. при котором должны грузиться объекты. Например расстояние 50 участков, грузить текстуру низкого качества и город, 20 кусков, грузить 2D деревья и пара крупных камне...(этот способ для вида от первого лица)

Beermonza 24.02.2009 14:39

Очевидно, Лубышев намекает на РПГ, от третьего лица, карта ползет плавно в противоположные стороны перемещению, а персонаж все время в центре экрана.
Если персонаж игрока все время в центре, то самый верный способ следить за радиусом обзора и подгружать ресурсы карты по мере их видимости. Подгрузка секторов карты уместна для 3D игр, где плавающая камера может перемещаться вплоть до режима от первого лица.
Если игра однопользовательская, то следить за всеми юнитами не нужно, можно лишь делать иллюзию изменения их состояния, как только взор главного персонажа достигнет их.

Maxadal 09.03.2009 00:57

Плавное перемещение юнита в игровой матрице и разрешение конфликтной ситуации с иными обьектами.
 
Всем привет!... Решился написать простенькую стратежку. Начал писать алгоритм на бумаге и возникло пару вопросов. Ломал голову дня 2 ничего оптимального в голову непришло!... вот подумал спросить у профессионалов...
Имеется игровое поле реализованное в квадратной матрице. После реализации алгоритма для поиска пути возникает несколько вопросов по плавному передвижению юниотов. ПРи движениии обьекта из пункта А в пункт Б возникла проблема алгоритма (будем считать что путь перемещения найден и записан к примеру в динамический массив). Пусть свободные ячейки помечены нулём, занятые иными номерами. Наш юнит к примеру имеет номер занятости 2 (если смотреть игровое поле). При плавном передвижении юниота в очередную ячейку(по найденому свободному пути) нееобходима переместить его не за один игровой ход а к примеру за 10 что соответствует его скороси перемещения, те за 10 шагов мы должны переместиться в искомую клетку., казалось бы никаких проблем если бы не 1 но!... Что делать если юнит произвел 4 сдвига (из этих 10) и графически со смещением находиться ещё в начальной позиции матрицы но при этом и до конца не достиг следующей клетки(те следующей ячейки матрицы в его пути). Он как бы находиться и там и там. И происходит некое событие. К примеру если эта клетка ещё не помечена как занятая то на неё могут претендовать другие юниоты как для перемещения так и для иных действий(??? это так ???). Вопрос что делать если в такой ситуации. На эту же (2-ю клетку) претендует другой юнит то есть он тоже хочет проити через неё или он например частично находиться на ней а частично на другой при этом для упращения будем считать что размер обьекта соответствует размеру клетки матрицы... пожалуйста если кто знает как реализоватьь алгоритм или какую - нибудь идею по этому поводу напишите пожалуйста. ПРи этом хочеться отметить что желательно бы учесть тот факт что хочу чтобы это всё выглядело более реалестьично поэтому будем считать что на одной клетке не могут находиться более 1 юниота. Хотелось бы хотяб услышать идею по этой теме или что ещё лучше простенький пример по этому поводу или алгоритм!

DeKot 09.03.2009 16:23

Допустим размер ячеек 50 х 50.Юнит находится в ячейке с координатами (Х=100,Y=100) и должен переместиться на на соседнюю ячейку
(150,100).По событию (нажатие клавиши вправо) делаете цикл и даете приращение по Х на 5 едениц.Получите плавное перемещение юнита.
Примерно так :
Код:

for i:= 1 to 10 do
begin
  // выводим фон вместо юнита в координате X,Y
  Х:= Х + 5;
  // в новых координатах выводим юнита (конечно желательно применять спрайты)
  // задержка (можно Sleep(50);)
end;


Beermonza 09.03.2009 17:25

Maxadal, все очень просто. Физически матрица - модель карты, сектора, грубые для графики. Каждый переход на клетку сопровождается плавным смещением объекта на 1 пиксел по-X и/или по-Y в нужном направлении, причем, графически мы точно знаем размер одной клетки на экране, допустим это 50х50 (таил). Достаточно задать цикл смещения на пол размера тайла, ...считается если объект находится в некоторой клетке со смещением 0, то он будет в ней находиться, пока смещение в цикле не станет больше пол размера тайла, в этом случае будет считаться, что объект перешел на следующую клетку, но при этом получил отрицательное смещение, которое будет стремиться к нулю (центру клетки на экране). Как только смещение стало равным 0, объект останавливается, если это пункт назначения в модели. Посмотри вот этот пост http://programmersforum.ru/showpost....&postcount=164 ...далее после него в разделе есть и пример.

Maxadal 10.03.2009 16:19

Вложений: 2
Предыдущие 2 ответа на мой вопрос тривиальны и не несут всебе необходимую информацию о сложившейся у меня проблеме ((( ... возможно я что-то не так обьяснил... теперь решил прикрепить 2 изабражения для полной оценки ситуации в ходе программы.. на первом рисунке изображена часть игрового поля (карты)... в ней я взял 3 елемента матрицы.. в верхней и нижней ячейках находиться по юниоту ... во 2-м изображении я показал ход их движения.. допустим юнит перемещаеться за 10 ходов в соседнюю клетку, это его скорость... допустим первым движение начал юниот1(или оба вместе)... так как запись его положения в пустую клетку произойдёт лишь когда он или они сделают по 5 перемещений из 10, то возникает вопрос как помечать и использовать такие клетки(в который он или они перемещаються)???... красный движеться к примеру сначала вниз а потом направо, а синиq только вверх или ещё как-нибудь, при этом нехотелось бы чтобы они находились в одной клетке вместе, как быть с отображением такого участка карты ведь клетка по центру сначала свободна и на неё движуться 2 или 3 юнита... а потом 1 из них перевым записался вэту клетку , что делать второму???... идти назад или как??? нехотелось бы также чтобы изображения этих юнитов накладывались друг на друга, или если юнит двидежеться к примеру со смещением влево на 5 шагов то он естественно будет "задевать" соседние элементы, что если на них переместиться некий обьект???

Beermonza 10.03.2009 22:21

Все именно так как и описал выше, ...ситуация один в один. Позиция в массиве - это не самый главный показатель присутствия на карте объекта. Это привязка к модели, модель - штука не визуальная, а вот смещение - это основной показатель, где графически расположен объект. Разбираем рисунки. Оба объекта одновременно идут навстречу друг к другу. Как известно, обработка объектов производится в цикле по очереди. Первым ячейку замет тот объект, что в списке объектов записан первее, ...сразу он получит координаты этой ячейки, но отрицательное смещение равное половине размера реальной клетки карты. Визуально он будет на пол пути до центра клетки, но по списку в этот такт обрабатывается следующий объект. В момент, когда смещение позволяет выполнить переход на клетку выше, условие видит, что клетка уже занята. В этот момент нужно останавливать движение нижнего объекта. В результате, верхний объект займет пустую ячейку массива, а нижний в массиве останется на том же месте, но графически по смещениям они встретятся на середине и остановятся.

Maxadal 11.03.2009 15:35

Beermonza, это теперь понятно... спасибо обьяснил на пальцах))... а если предположить что к примеру верхний обьект идёт слева или справа а нижний двигаеться так же... ведь когда они начнут двигаться в одну и ту же клетку то получиться что они будут "наезжать" друг на друга углами(графически)??? ... если это так то что делать в такой ситуации???

Beermonza 11.03.2009 15:58

Maxadal, обрати внимание, ...я в предыдущем посте употребил фразу "...условие видит, что клетка уже занята." - это система "радиуса обзора". Т.е. обработка каждого объекта включает в себя проверку соседних клеток и смещений объектов, что в них находятся. Это часть системы поиска пути. Частный случай, когда "верхний объект идёт слева или справа, а нижний двигается так же", как ты предположил, первый должен остановиться, если графическое смещение второго уже не позволяет первому пройти. Если пройти еще можно, то первый будет идти, а второй "наткнувшись" на недопустимое смещение первого, остановится, будет ждать когда путь освободится, или начнет обходить, ...но это уже к полноценной системе "поиска пути" относится. StarCraft припоминаешь? ...как там танк может проехать между двумя строениями людей, наехав гусеницами на спрайт строения :) ...недочет небольшой, ...да кому это вообще интересно ковырять, игра-то хит!
А что за стратегия, вид сверху, или изометрия?

Maxadal 11.03.2009 16:09

Я ещё на "измене"... ))) ... охота конечно изметрию... но с другой с тороны стоит попробовать что полегче... первый раз игру пишу до этого с графикой мало работал... хочу курсовой себе на такую тему попробовать написать ... теперь вот сижу думаю, что использовать DirectX или обойтись стандартными возможностями... спасибо за помощь...

Алекс Ялта 14.03.2009 19:41

за что функция отвечает?
 
Учусь использовать canvas по урокам, которые предоставлены в этой теме. В посте № 105 приведен пример игры, в которой шарик плавно перемещается по карте из клеток, созданной из массива. Разбираю код. Всё ясно кроме назначения этой функции:
Код:

function keypressed(key: byte): boolean;
var
  keys: TKeyboardState;
begin
  result:=false;
  GetKeyboardState(keys);
  if(keys[key]=128)or(keys[key]=129)then result:=true;
end;

что за кнопки под номерами 128 и 129? "if(keys[key]=128)or(keys[key]=129) then result:=true;"

Beermonza 14.03.2009 21:27

128 и 129 - это код не клавиши, а что клавиша с кодом key нажата, 128 - клавиша нажата четный раз, 129 - нечетный раз, оба значения - "факт, клавиша нажата". Также для не нажатой клавиши значение 0 и 1.

Алекс Ялта 15.03.2009 15:31

Теперь всё стало ясно. Спасибо

Maxadal 17.03.2009 10:30

Кто знает как можно вывести часть спрайта в DirectX без использования directdraw ???...

Kostia 17.03.2009 12:30

Maxadal, к сожалению никак. Но если сильно нужно, то можно программно разделить одну большую текстуру на несколько маленьких или заранее раздробить на несколько файлов.(если Direct3D имелся ввиду)

Maxadal 17.03.2009 12:40

Да я имел ввиду Direct3D... просто я незнаю как мне сделать прокрутку игровай карты если использовать DirectX ... и чтобы можно было невыводить часть спрайта... я просто незнаю как тогда организовать интерфейс меню в игре??? и вывод карты с прокруткой...

Kostia 17.03.2009 12:56

Эх, надеюсь не забанят.
http://delphideveloper.narod.ru/
Сайт на фреймах поэтому прямой ссылки дать не могу. Pascal/Delphi -> Delphi,Direct3D,2D -> 1. Определение поддерживаемых режимов монитора...

Maxadal 17.03.2009 12:59

Боольшое спасибо попробую разобраться)

Beermonza 17.03.2009 15:52

Maxadal, это ты миникарту в уголку реализуешь или что?

AlDelta 17.03.2009 18:14

Цитата:

я незнаю как мне сделать прокрутку игровай карты
Нет, у него игровое пространство больше чем размеры экрана.

Банальное нежелание пользоваться поиском по форуму...

Beermonza 17.03.2009 22:55

Выводить 2D на экран посредством Direct3D - это просто кощунственно по отношению к нему, и для каких грандиозных целей он был создан :)
Вообще все просто. Нужно создать большой спрайт участка карты, чуть больше экрана, и банально грузить на него изменяющуюся текстуру поверхности, которая строится исходя из модели поверхности под ногами. Камера, надеюсь, не плавает? В моменты перехода на клетку (а карта смещается так же как и объект, по клетке матрицы, с плавным смещением) происходит сканирование определенного участка матрицы всей карты (модель с параметрами, которой не видим) и вывод на наш фрагмент - спрайт видимого участка. Сама текстура собирается по кусам.

Алекс Ялта 20.03.2009 23:25

Collision Bitmap'ов на канве
 
Столкнулся с проблемой. Как проверить столкновение объектов Bitmap на канве. В теории я понимаю, что нужно проверять на столкновение углы прямоугольников. Но, если, у меня есть объект Bullet (Bitmap - пуля) с координатами BulletX,BulletY, который я отрисовываю в буффер так Buffer.canvas.Draw(BulletX,BulletY, bullet) и объект Enemy, с координатами Ex,Ey , как должен выглядеть код?
Я пробовал,к примеру, так (проверка только по оси Y)

Код:

procedure Collision1();
begin
If ((BulletX,BulletY)>=(Ex,Ey)) or ((BulletX+10,BulletY)>=(Ex+40,Ey))
then EnemyDestroy;
end;

программа не компилируется и ругается " ')' expected but ',' found "

DomiNick 20.03.2009 23:30

Цитата:

" ')' expected but ',' found "
Дословно с английского означает: "должна быть скобка, а обнаружена запятая"... :))
Ты просто скобку где-нибудь пропустил... :)


Дополнение

Так... А что это за условие такое странное "((BulletX,BulletY)>=(Ex,Ey)) or ((BulletX+10,BulletY)>=(Ex+40,Ey))" ..?

Может лучше так:
Код:

If ((BulletX+60>Ex) And (Ex+60>BulletX)) And ((BulletY+60>Ey) And (Ey+60>BulletY)) Then
Там два битмапа 60х60...

Beermonza 21.03.2009 00:18

Все нужно выполнять в модели, а отрисовка подчиняется изменению состояния модели. Т.е. мы работаем с цифрами, ...в клетке X,Y должна лететь пуля в таком-то направлении, ...создаем ее на карте под кодом, задаем направление, допустим по-Y вверх, в таймере обработки всех объектов, объект "пуля" с текущими координатами X,Y отнимает от Y ее скорость Speed, и постепенно "летит" по матрице карты, начисляя себе смещения и сменяя клетку, как только смещение упирается в конец. Таким образом, тот кто попадет в одну из клеток на пути перемещения пули будет поражен, это из условия (если в клетке есть объект, то травмировать его). Графика строится в конце цикла обработки объектов, ...перебираются клетки карты, и если там записаны объекты, то нарисовать их с их свойствами, где был, какое смещение, какая анимация, какой кадр и пр. пр. пр.

Алекс Ялта 21.03.2009 10:30

Цитата:

Сообщение от DomiNick (Сообщение 224817)

Дополнение

Так... А что это за условие такое странное "((BulletX,BulletY)>=(Ex,Ey)) or ((BulletX+10,BulletY)>=(Ex+40,Ey))" ..?

Может лучше так:
Код:

If ((BulletX+60>Ex) And (Ex+60>BulletX)) And ((BulletY+60>Ey) And (Ey+60>BulletY)) Then
Там два битмапа 60х60...

Конечно же так лучше) Только Битмап пули я сделал 10х10 и хотел задать коллизию без построения поклеточного уровня. Как задать коллизию на карте, составленного из клеток, я понимаю. Я думал, что возможно просчитать столкновение по координатам т.н. вершин прямоугольников(или рамок), как это делается в DelphiX.

Алекс Ялта 21.03.2009 13:45

Извиняюсь перед всеми, кому задурил голову) И снова DomiNick был прав. Пока не начертил на бумаге эскиз с координатами, не понял сути. Мне нужна простая коллизия по оси Y. Поэтому код такой:
Код:

procedure collision();
begin
if (BulletX+10>=EnemyX) and (bulletX<=Enemyx+30)
and (BulletY<=EnemyY+30)
then begin
BulletDestroy;
EnemyDestroy;
end;


Kostia 22.03.2009 10:46

А вообще запомните такую формулу:
Код:

if (x>=objx) and (y>=objy) and (x<=objx+objwidth) and (y<=objy+objheight) then
Проверка попадания точки (x,y) в прямоугольник (objx, objy, objx+objwidth,objy+objheight);
А попадание точки в окружность определяется так:
Код:

if sqrt(sqr(x-objx)+sqr(y-objy))<=r then
Проверка попадания точки (x,y) в окружность с центром (objx, objy) и радиусом r

Алекс Ялта 22.03.2009 20:44

Спасибо. Пригодится

Shadow_1329 23.03.2009 10:10

У меня один вопрос. Игра-стрелялка. Мне нужро сделать чтобы пуль вылетало бесконечно много. Рисую на Canvas. У пули есть координаты x и y, и таймер её прорисовывает туда, куда показывает x или y. Но пуля тока одна, а мне нужно много. Как это осуществить? Ставить бесконечно много обработчиков событий для пуль??

Алекс Ялта 23.03.2009 11:04

Цитата:

Сообщение от Shadow_1329 (Сообщение 225945)
У меня один вопрос. Игра-стрелялка. Мне нужро сделать чтобы пуль вылетало бесконечно много. Рисую на Canvas. У пули есть координаты x и y, и таймер её прорисовывает туда, куда показывает x или y. Но пуля тока одна, а мне нужно много. Как это осуществить? Ставить бесконечно много обработчиков событий для пуль??

Насколько я помню, в постах 150-160 этого раздела рассматривается пример создания собственного типа. Можно попробовать создать тип Bullet и массив
Код:

MasBullet: array [1..255] of Tbullet;
И вопрос такого плана нужно задать в той теме для получения более эффективного ответа

ROD 23.03.2009 12:13

Цитата:

У меня один вопрос. Игра-стрелялка. Мне нужро сделать чтобы пуль вылетало бесконечно много. Рисую на Canvas. У пули есть координаты x и y, и таймер её прорисовывает туда, куда показывает x или y. Но пуля тока одна, а мне нужно много. Как это осуществить? Ставить бесконечно много обработчиков событий для пуль??
Можно сделать их с помощью списка ( в этом случае количество выпущеных пуль ограничивается лишь памятью компьютера)
При выпускании пули она добавляется в конец списка, при попадании, она удаляется их списка. (т.е. функци-обработчик пуль работает не с каждой отдельной пулей, а со списком пуль).

К стати, таким же способом можно сделать бесконечное число простивников. (хотя противников я бы делал классами, что бы каждому можно было сделаь индивидуальное поведение (ну что бы они не по прямой летели, а зигзагами, стреляли и т.п (впрочем если делатьк акие-то специфические патроны (типа самонаводящихся ракет или осколочных гранат), тот тут тоже классами делать нужно)).)

Shadow_1329 23.03.2009 14:59

А как это списками? Чо то я не вкупил.

Boris96_2007 27.03.2009 10:25

А в какой программе это всё прописывать?

Pyton 27.03.2009 14:32

В данном разделе все делается на Делфи.

Kostia 27.03.2009 22:06

Вложений: 1
Цитата:

У меня один вопрос. Игра-стрелялка. Мне нужро сделать чтобы пуль вылетало бесконечно много. Рисую на Canvas. У пули есть координаты x и y, и таймер её прорисовывает туда, куда показывает x или y. Но пуля тока одна, а мне нужно много. Как это осуществить? Ставить бесконечно много обработчиков событий для пуль??
Изучаем данный код и становимся гуру: http://pblog.ru/lab/?p=106
________
А это упрощенный TList:

Алекс Ялта 31.03.2009 18:24

Универсальная проходимость карты
 
Никак не могу осилить. Как задать универсальную проходимость на карте? Изучил все примеры, которые находятся в этой теме. Неужели нужно делать ДВА массива карты? Один под проходимость, а другой под текстуру. Имееется ввиду карта с большим колличеством текстур и с разной проходимостью. Я понимаю как задать проходимость и текстуру на один индекс. То есть, если из файла считал индекс "1", то: ходить нельзя, текстура 1.bmp. В то же время прописывать под дополнительные обозначения свою проходимость мне кажется неправильным. К примеру, если карта имеет такой вид в текстовом файле:
11111111111111111
10000000000000001
10244300000000001
10000050000000001
10000005000000001
11111111111111111

Места под номерами 2,3,4,5 будут НЕ ПРОХОДИМЫМИ и все будут иметь разные тестуры. Как в таком случае будет выглядить код?
Если создать тип карты:

Код:

type
  TGameMap = packed record
    p:      byte;      // Проходимость
    Tex:    TBitmap;    // Текстура клетки
  end;

Сам массив карты будет таким
Код:

var
map: array [1..20,1..15] of TGameMap;

В такой процедуре загрузки уровня индекс проходимости будет
сответствовать индексу текстуры:

Код:

//...............................
 for j:=1 to 20 do
        for i:=1 to 15 do begin
            Read(Map[j,i].p); // р - проходимость
            Map[j,i].Tex:=TBitmap.Create;  // Tex - текстура клетки
            Map[j,i].Tex.LoadFromFile('img\'+IntToStr(Map[j,i].p)+'.bmp');
            BackBuf.Canvas.Draw(j*32-32, i*32-32, Map[j,i].Tex);
//.................................

Как в таком случае быть? Прописывать проходимость дополнительно наподобии:
Код:

if p=1 or if p=2 or if p=3.....  then
ходить нельзя?

Levsha100 31.03.2009 18:47

Цитата:

Сообщение от Алекс Ялта (Сообщение 231855)
Код:

type
  TGameMap = packed record
    p:      byte;      // Проходимость
    Tex:    TBitmap;    // Текстура клетки
proxodimo:boolean;
  end;


Для ускорения можно сделать так...

Алекс Ялта 31.03.2009 19:04

Цитата:

Сообщение от Levsha100 (Сообщение 231861)
Для ускорения можно сделать так...

Сути не меняет. На этот же индекс не получится записать другую текстуру.

Beermonza 31.03.2009 19:54

Про загрузку и использование текстур и проходимости...
 
Это пример с поста #102, если не ошибаюсь. Пример простейший. Задача стоит по-иному: если много текстур, как вместить проходимость?
Будем предельно точны, расширим представления о системе хранения текстур и проходимостей. У нас есть база текстур, в виде одномерного массива, в котором загружены все текстуры, что есть на карте, ...как? ...пробегаем по массиву карты, что был загружен с файла, смотрим каждую цифру, и записываем последовательно в массив Bitmap с файла текстуры. Дополнительно в коде каждой клетке зашифрована и проходимость, ...как? ...допустим мы берем 256 текстур - это много, половина из них проходимые, половина нет, или даже 3 степени проходимости: 0 - можно идти, 1 - нельзя ни при каких условиях, 2 - можно при определенных условиях. В итоге у нас:

0 - 99 - номера текстур, по которым можно ходить;
100 - 199 - номера текстур, по которым нельзя ходить;
200 - 255 - номера специальной проходимости.

Вернемся к загрузке текстур. Проверяя очередную клетку выполняем условия:

если число < 100, то ставим в запись проходимости 0;
если число > 99 но < 200, то ставим в запись проходимости 1;
если число > 199, то ставим в запись проходимости 2;

Попутно с файла загружаются текстуры с именами, равными числам, таким образом тип банка текстур становится справедливым:
Код:

type
  TTexBank = packed record
    Tex:    TBitmap;    // Текстура клетки
// тут еще масса параметров текстуры
    DispX:  Byte;        // Смещение по-X
    DispY:  Byte;        // Смещение по-Y
// если есть анимация
    MaxFrame:  Byte;  // количество кадров
    Frame:      Byte;  // текущий кадр
// и еще, что нужно....
  end;

Назначая тип на массив, мы представляем все текстуры в виде индексов привязки:
Код:

TexMas: array[0..255] of TTexBank;
У нас 256 индексов текстур. Теперь, куда идет проходимость? ...она идет в тип карты:
Код:

Type
  TGameMap = packed record
    Move:    Byte;      // Проходимость
    Index:    Byte;    // Индекс текстуры
  end;

Массив карты двумерный:
Код:

MapMas: array[1..20,1..15] of TGameMap;
Что происходит? Текстура много раз повторяющаяся на карте хранится в единственном экземпляре в массива TexMas, а массив MapMas хранит проходимость и индекс текстуры. Теперь когда мы будем рисовать карту мы напишем так:
Код:

Buf.Canvas.Draw(x,y,TexMas[MapMas[i,j].Index].Tex);
Если нужно проверить, может ли объект двигаться в клетку, проверим содержимое MapMas[i,j].Move, и через условия разрешим двигаться или нет. Сейчас там могут быть 3 значения: 0, 1 и 2.

Как записать на карту числа уже весом в 3 байта? (0 - 9 весят 1 байт, 10 - 99 весят 2 байта, 100 - 255 весят 3 байта) ...ответ в вопросе, перейдем к хранению данных в байтах:
Код:

MamFile: File of Byte;
Надеюсь этого хватит? ...если нет, то есть способ с вложением данных о текстуре, это отдельные файлы, текстового типа (TextFile) с именем файла текстуры, ...в них проходимость записана, и при считывании файла текстуры одновременно считываются и данные о текстуре и записываются в проходимость. Не хватит этого, вводите еще один байт на код текстуры, это уже 65536 видов текстур.

Алекс Ялта 31.03.2009 20:07

Огромное спасибо. Я думаю, этого достаточно. Осталось переварить информацию

Алекс Ялта 01.04.2009 12:32

Цитата:

Сообщение от Beermonza (Сообщение 231921)

Как записать на карту числа уже весом в 3 байта? (0 - 9 весят 1 байт, 10 - 99 весят 2 байта, 100 - 255 весят 3 байта) ...ответ в вопросе, перейдем к хранению данных в байтах:
Код:

MamFile: File of Byte;

То есть в текстовом файле карты lvl.txt нужно обозначать числа, разделяя их пробелом?

001 002 003 055 066 077
111 112 113 114 115 116
117 118 119 120 121 122

а потом связывать текстовый файл с файлом байтов (MamFile: File of Byte;)?

Код:

AssignFile(MamFile,'lvl.txt');
(Не бейте ногами сходу, если вопрос выглядит очень глупо. Просто очень тяжело усваивается)

Beermonza 01.04.2009 15:27

Цитата:

Сообщение от Алекс Ялта
(Не бейте ногами сходу, если вопрос выглядит очень глупо. Просто очень тяжело усваивается)

Строгий выговор как минимум.

Если файл байтовый, значит он содержит байты, которые представляются в виде символов, каждый из которых может определять число от 0 до 255. Если открыть любой файл EXE в проводнике, то можно увидеть кучу "иероглифов" - это и есть представление чисел типа Byte.

Цитата:

Сообщение от Алекс Ялта
То есть в текстовом файле карты lvl.txt нужно обозначать числа, разделяя их пробелом?

001 002 003 055 066 077
111 112 113 114 115 116
117 118 119 120 121 122

Будем бить ногами :) ...нерационально до безумия. Никаких пробелов, и нулей, все в кучу, и на одну клетку один байт (или два). Примерно так:

[hщык$4KЏЂуU¬«@c

Заметно разницу в весе? ... 18 байт, ...у тебя 72 байта (переходы на строку тоже в счет), и при том, что карта мизерная совсем. Всегда следи за "весом" ресурсов, негоже раскидываться памятью, если в том нет надобности.
Значит все байты идут подряд, без пробелов, ...мы же четко знаем, что один байт - одна клетка, ненужны пробелы, будем выполнять команду чтения одного байта Read. Записываем в цикле:

Код:

for i:=1 to 20 do
  begin
    for j:=1 to 15 do
      begin
        Read(f, b);
// тут проверка массива текстур,
// если такая текстура уже загружена,
// ставим ее индекс в MapMas[i,j].Index
      end;
  end;

По поводу этого кода, ...тут не все просто, попробую упростить, и привести пример проверки массива текстур, ...чуть позже.

Алекс Ялта 01.04.2009 22:30

Уважаемый Beermonza, спасибо за разжевывание информации. С байтами я уяснил преимущества. Создал редактор карты и с его помощью записываю в одну строку байты в текстовый файл карты.
Цитата:

Сообщение от Beermonza (Сообщение 232424)
Код:

for i:=1 to 20 do
  begin
    for j:=1 to 15 do
      begin
        Read(f, b);
// тут проверка массива текстур,
// если такая текстура уже загружена,
// ставим ее индекс в MapMas[i,j].Index
      end;
  end;

По поводу этого кода, ...тут не все просто, попробую упростить, и привести пример проверки массива текстур, ...чуть позже.

Если будет время, приведите, пожалуйста, пример.

Beermonza 02.04.2009 16:50

Подробно о заполнении банка текстур...
 
Сначала как всегда "на пальцах" немного теории. Цель - загрузить текстуры в банк, исходя из кода, считанного с файла, и не допустить дублирования, если в этом нет надобности. Логически все выглядит так. У нас есть некий файл карты, мы можем его "читать" по одному байту. У нас есть одномерный массив, в который мы будем записывать текстуры. Очевидно, что понадобится перебор банка текстур, с целью поиска уже существующей текстуры по коду карты. А если текстура так и не была найдена на переборе до ближайшей свободной ячейки банка, то значит нужно записать ее в эту первую свободную ячейку, после всех занятых. Чтобы долго не кувыркаться со стандартными командами, добавим в тип банка две записи Name и TexUses:
Код:

type
  TTexBank = packed record
    Tex:    TBitmap;    // Текстура клетки
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    Name: Byte;          // Реальный код текстуры
    TexUses: Boolean;  // Используется ли ячейка
// --------------------------------------
// тут еще масса параметров текстуры
    DispX:  Byte;        // Смещение по-X
    DispY:  Byte;        // Смещение по-Y
// если есть анимация
    MaxFrame:  Byte;  // количество кадров
    Frame:      Byte;  // текущий кадр
// и еще, что нужно....
  end;

В начале каждого считывания карты, нужно пробежаться по всему массиву банка и стереть данные:
Код:

for t := 0 to 255 do
  begin
// Bitmap удален из памяти
    TexMas[t].Tex.Free;
// Подготовлено место
    TexMas[t].Tex := TBitmap.Create;
// Ячейка не используется
    TexMas[t].TexUses := False;
  end;

Теперь, как выглядит алгоритм заполнения текстурами банка:
Код:

for i:=1 to 20 do
  begin
    for j:=1 to 15 do
      begin
        Read(f, b);
// новый цикл проверки банка текстур, проверяет занятые ячейки
// работает, пока не встретит пустую ячейку, если встретил,
// значит не нашел текстуры.
        t := 0;
        while TexMas[t].TexUses do
          begin
// если нашлась нужная текстура
            if TexMas[t].Name = b then
              begin
// записываем условный индекс в массив карты
                MapMas[i,j].Index := t;
// переход
                GoTo M;           
              end; 
// счетчик
            Inc(t);
          end;

// если цикл поиска не нашел текстуру, то он остановился
// на свободной ячейке.
// привязка к текущей ячейке
        MapMas[i,j].Index := t;
// имя текстуры
        TexMas[t].Name := b;
// загрузка текстуры (каталог Textures в папке проекта)
        TexMas[t].Tex.LoadFromFile('Textures\'+IntToStr(b)+'.bmp');
// ячейка занята
        TexMas[t].TexUses := True;
       
// сюда переход, если текстура определилась
M:
      end;
  end;

Надеюсь ошибок нет, проверяйте, ...выложил код теоретически, без проверки, по аналогии работающего сложного кода.
С переходами GoTo работать просто, нужно только указать в процедуре, перед ее началом (begin) запись метки: Label M;

IvaniuS 05.04.2009 13:57

Вложений: 3
са сейчас мучаюсь пока ничего невышло если выйдет напишу как смастерил, по последнему посту вообще неполучаеться хотя подход правельный я всё понимаю но реализовать немогу программа не та.
щас пользуюсь просто вот таким масивом
Код:

map: array of array of byte;
он меня почти устраивает и проходимость реализую через: карту в карте 2 вида стен 1-ый:1, 2-ой:2 и в цикле когда строю текстуры если 1 то проходимость :=1 если 2ой то 0.
а в программе уже зависимость от проходимость про проверке след клетки
да вот мой цикл считавания:
Код:

Reset(f);
  Read(f,MapW);
  Read(f,MapH);
  SetLength(map,MapW+2,MapH+2);
 for y:=1 to MapH do
    for x:=1 to MapW do
    begin
        read(f,map[x,y]);
 if map[x,y]=1 then
        proh[x,y]:=1;

короче есть 2 проги хочу или в одной сделать управление мышкой или во второй загрузку текстур с картой
вот что у мну получаеться
КОРОЧЕ МЕНЯ ВСЕ уже достало дайте простой пример проги чтобы просто загружалась карта пусть даже с 2 обьектами, любое управление 1 обьект фон 2 ой непроходимый так будет понятнее

Алекс Ялта 05.04.2009 18:08

Прозрачность спрайтовой анимации
 
Вложений: 1
Разбираюсь со способами вывода анимации на форму при помощи спрайтов, размещенных в едином Битмапе. У меня при выводе анимации каждый последующий кадр просто накладывается на предыдущий. Не могу понять как в таком случае затирать предыдущий кадр фоном? Код такой:
Код:

var
  Form1: TForm1;
  Buffer: Tbitmap;
  fon: Tbitmap;
  Expl: Tbitmap;
  boom: boolean;
  x,y:integer; // координаты размещения взрыва
  i:byte; // номер кадра

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
Buffer:=Tbitmap.Create;
Buffer.Width:=400;
Buffer.Height:=300;
Buffer.Transparent:=true;
Buffer.TransparentColor:=clWhite;

Fon:=Tbitmap.Create;
Fon.LoadFromFile('pic/fon.bmp');

Expl:=Tbitmap.Create;
Expl.LoadFromFile('pic/expl.bmp');
expl.Transparent:=true;
x:=50;
y:=50;
i:=0;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
Buffer.Canvas.Draw(0,0,fon);

if boom then begin

Buffer.Canvas.CopyRect(bounds(100,100,36,36),Expl.Canvas,bounds(i*36,0,36,36));
//  (bounds(100,100,36,36) - 100,100: положение взрыва на картинке буфера
                          //36,36: размер области, в которую вставим, скопированный кусок
i:=i+1;
if i>9 then begin
i:=0;
boom:=false;
end;
end;
Buffer.Canvas.Draw(0,250,expl);
Form1.Canvas.Draw(0,0,Buffer);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if boom=false then boom:=true;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Buffer.Free;
Fon.Free;
Expl.Free;
end;

end.

Вот исходник с битмапами:

IvaniuS 05.04.2009 18:32

Вложений: 1
щас выложу пример там всё расписано с этим у меня проблем нету а вот с мапой никак не разбирусь ппц(
вот код и пример:
Код:

// "кидаем" в буфер кадра задний фон карты
  Buf.Canvas.Draw(0,0,BackBuf);
// смена кадра если персонаж идет
  t:=t+1;
  if (Pers.TypeAnim > 0) and (t > 10) then
    begin
      inc(Pers.Kadr);
      if Pers.Kadr > Pers.MaxKadr then Pers.Kadr:=1;
      t:=0;
    end;

// если персонаж стоит, то анимация одного из кадров
  if Pers.TypeAnim = 0 then
    begin
      Rect2.Left:=(2-1)*Pers.TexWidth;
      Rect2.Top:=(3-1)*Pers.TexHeight;
      Rect2.Right:=Rect2.Left+Pers.TexWidth;
      Rect2.Bottom:=Rect2.Top+Pers.TexHeight;
    end
// иначе в соответствии со сменой кадров и типом анимации
  else
    begin
      Rect2.Left:=(Pers.Kadr-1)*Pers.TexWidth;
      Rect2.Top:=(Pers.TypeAnim-1)*Pers.TexHeight;
      Rect2.Right:=Rect2.Left+Pers.TexWidth;
      Rect2.Bottom:=Rect2.Top+Pers.TexHeight;
    end;

// готовим участок текстуры анимации персонажа (вырезаем кадр)
  PersAnimTex.Height:=Pers.TexHeight;
  PersAnimTex.Width:=Pers.TexWidth;
  PersAnimTex.Canvas.CopyRect(Rect1,Pers.Pic.Canvas,Rect2);

// рисуем в буфере кадра персонажа в нужном месте
  Buf.Canvas.Draw( Pers.PosX*Rax                      // положение по-X
                  + Pers.MoveX                        // смещение по-X
                  + Round(Abs(Rax-Pers.TexWidth)/2)    // центрирование по-X
                  , Pers.PosY*Ray                      // положение по-Y
                  + Pers.MoveY                        // смещение по-Y
                  + Round(Abs(Ray-Pers.TexHeight)/2)  // центрирование по-Y
                  , PersAnimTex);                      // граф. изображение кадра анимации персонажа

// выводим кадр на экран (в форму)
  Form1.Canvas.Draw(0,0,Buf);


Алекс Ялта 05.04.2009 18:37

Спасибо. Пример Очень расширенный) На самом деле всё оказалось проще чем я думал. Нужно создать дополнительный буффер, в котором задается прозрачность и её цвет. В этот буффер отрисовывается кадр, а буффер рисуется в основной буффер программы.

IvaniuS 05.04.2009 18:42

это уже давным давно надо было использовать с сапого начало создать буфер и внём могое отрисовывать у можеш небольшой пример загрузки карты привести или сказать что в моём непрально? щас выложу
у меня или нерисуеться вообще или ошибка в самом приложении когда её закрываеш то она исчезает
вот он по моему всё должно строиться:
Код:

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    procedure Timer1Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  map:array[1..500,1..500] of byte;
  MapW,MapH: byte; //размары карты
  gx,gy: integer; //смещение карты по x и y, их мы будем прибывлять к каждобу объекту на карте
  mapbmp: tbitmap; //буфер
  sx,sy: real; //скорость по x и y
  xp,yp: real; //позиция игрока на экране(в пикселах)
  x,y: integer;
  level: integer;//уровень
  brick0: tbitmap; //проходимые кирпичи(задний план)
  brick1: tbitmap; //не проходимые кирпичи
implementation

{$R *.dfm}
procedure loadlevel();
var
  f: file of byte;

begin
  sx:=0; sy:=0;
  if not FileExists('levels/'+inttostr(level)+'.txt')then
  begin
    level:=1;
  end;
  AssignFile(f,'levels/'+inttostr(level)+'.txt');
  Reset(f);
  Read(f,MapW);
  Read(f,MapH);
  for y:=1 to MapH do
    for x:=1 to MapW do
    begin
        read(f,map[x,y]);
    end;
  CloseFile(f);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
loadlevel;
  brick0:=TBitmap.Create;
  brick0.LoadFromFile('gfx/brick0.bmp');
  brick1:=TBitmap.Create;
  brick1.LoadFromFile('gfx/brick1.bmp');
 mapbmp:=TBitmap.Create;
 mapbmp.Width:=form1.Width;
 mapbmp.Height:=form1.Height;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  //  if ((gx+x*16-16<=form1.Width)and(gx+x*16>=0))or((gy+y*16-16<=form1.Height)and(gy+y*16>=0))then
вот ошибко, этого небыло дана было добавить и всё пашет:{for y:=1 to MapH do
    for x:=1 to MapW do}

case map[x,y] of
      0: {проходимая стена} mapbmp.Canvas.Draw(gx+x*16-16,gy+y*16-16,brick0);
      1: {не проходимая стена}mapbmp.Canvas.Draw(gx+x*16-16,gy+y*16-16,brick1);
 end;
  form1.Canvas.Draw(0,0,mapbmp);
end;

end.

строиться ток 1 кирпич неизвестно где

Алекс Ялта 05.04.2009 19:40

Вложений: 1
Вот тебе пример построения карты. Взят из этой же темы из ранних постов. Карта представлена не байтами. Всё проще. Изучи.
Твоя ошибка в том, что ты взял усложненный готовый код программы и пытаешься его адаптировать под свою программу.

IvaniuS 05.04.2009 20:24

Цитата:

Сообщение от Алекс Ялта (Сообщение 235151)
что ты взял усложненный готовый код программы и пытаешься его адаптировать под свою программу.

все виды пробовал даже отдельно сам писал отдельно на пару картинок получаеться, а внедрить некак(((
Я СДЕЛАЛ грац меня:) короче говоря я просто напросто не считывал и всё:) нада было добавить цикл для считывания хотя в примерах его нету и как оно пашет я хз(

Beermonza 05.04.2009 22:14

IvaniuS, а зачем для построения карты нужен таймер?

Цитата:

Сообщение от Алекс Ялта (Сообщение 235109)
Спасибо. Пример Очень расширенный) На самом деле всё оказалось проще чем я думал. Нужно создать дополнительный буффер, в котором задается прозрачность и её цвет. В этот буффер отрисовывается кадр, а буффер рисуется в основной буффер программы.

Что-то я не догнал логику действий. Нужен один буфер кадра, на нем все рисуется, ...нужен битмап сборного заднего фона, размером как буфер, ...и спрайты с заданным ключом прозрачности.
Происходит так:
1) По кускам собирается задний фон, один раз для определенного участка карты, и хранится пока не будет произведено смещение по карте;
2) Фон перекидывается в буфер кадра каждый раз вначале цикла отрисовки каждого кадра. Он кладется поверх, затирая все что было в буфере;
3) В цикле накладываются спрайты объектов, с анимацией или без. Каждый спрайт, суть, Bitmap, ему можно задать прозрачность и ее цвет.
4) Через Canvas или BitBlt() буфер кадра выводится в форму.

IvaniuS 06.04.2009 00:47

Цитата:

Сообщение от Beermonza (Сообщение 235259)
IvaniuS, а зачем для построения карты нужен таймер?

как это для обновление если произошли изменения, в картостроении ваще хз зачем он если можно обрабатывать онклик.
у меня после всего а у меня все получилось даже больше есть 2 вопроса:
1:проблема с размером бмп хочу использовать 64х64 рачество заметно возрастает весит мало под сжатием а он отображаеться как 16х16 всеравно, как в программе это изменить?
2:проблема с масивом типа байт если обьектов много больше 10 что делать? трехзначные использовать значения чтоли или двух? а уже к ним присваивать название? это же полный бред, как-то видел прогу "моя третя гра" там какойто формат карты очень хороший хочу типа такого прогу сделать
ОТВЕЧАЮ НА 1 ВОПРОС СВОЙ: у каждой текстуры есть "программный размер" Tex.Width Tex.Height которые можно менять

Алекс Ялта 06.04.2009 13:05

Цитата:

Сообщение от IvaniuS (Сообщение 235351)

2:проблема с масивом типа байт если обьектов много больше 10 что делать? трехзначные использовать значения чтоли или двух? а уже к ним присваивать название? это же полный бред, как-то видел прогу "моя третя гра" там какойто формат карты очень хороший хочу типа такого прогу сделать

Существет 2 варианта решения проблемы на данном этапе)
1. Простой вариант: при использовании на карте символов char (map: array [1..X,1..Y] of char; ) можно кроме цифры использовать латинские символы a,b,c,d...z
2. Вариант посложнее: отлистнуть страницу назад и изучить информацию с поста 267

Алекс Ялта 06.04.2009 15:05

Цитата:

Сообщение от Beermonza (Сообщение 235259)

Что-то я не догнал логику действий. Нужен один буфер кадра, на нем все рисуется, ...нужен битмап сборного заднего фона, размером как буфер, ...и спрайты с заданным ключом прозрачности.

Это я и имел ввиду. Но выразился неправильно) Я поначалу пытался вывести кадр на общий битмап сборного заднего фона.

Beermonza 06.04.2009 15:38

Цитата:

Сообщение от IvaniuS (Сообщение 235351)
как это для обновление если произошли изменения, в картостроении ваще хз зачем он если можно обрабатывать онклик.
у меня после всего а у меня все получилось даже больше есть 2 вопроса:
1:проблема с размером бмп хочу использовать 64х64 рачество заметно возрастает весит мало под сжатием а он отображаеться как 16х16 всеравно, как в программе это изменить?
2:проблема с масивом типа байт если обьектов много больше 10 что делать? трехзначные использовать значения чтоли или двух? а уже к ним присваивать название? это же полный бред, как-то видел прогу "моя третя гра" там какойто формат карты очень хороший хочу типа такого прогу сделать

Если карта не двигается, то весь задний фон, суть - картинка, собирать каждый кадр заново не нужно. Массив карты тоже не обновляется, каждый раз - это статика. По таймеру на задний фон в буфере накладываются объекты игры, те что могут двигаться или не могут, но анимированы. Если произошел сдвиг по карте, то запускается процедура обновления заднего фона, и соответственно диапазон выборки ячеек массива карты.
1) Посмотри как ты использовал отрисовку:
Код:

case map[x,y] of
      0: {проходимая стена} mapbmp.Canvas.Draw(gx+x*16-16,gy+y*16-16,brick0);
      1: {не проходимая стена}mapbmp.Canvas.Draw(gx+x*16-16,gy+y*16-16,brick1);
 end;

Число 16 - не константа, вместо нее нужно записать размеры твоих спрайтов, соответственно Tex.Width для X и Tex.Height для Y.
2) Смотри посты #265 - #270

Послесловие: IvaniuS, пиши грамотно.

IvaniuS 06.04.2009 15:45

к счастью я вчера ночью разобрался со всем косаюмщимся карты,
нашёл замену размеров и многое другое точ но нужно было, сейчас видел редактор он записывает в файл через пробел числа которые что-то означают согласитесь небольшая карта весит 25Мб + это непонятный набор цифр.
ВОПРОС: нельзя использовать карты сторонних разработчиком например КС, ВАР-КРАФТ, ЕЕ1-3(Емперия), Диабло и т.д. можно до бесконечности перечислять и как их использовать т.е. это нужно искать исходник и разбираться или разбирать саму карту или сторонние компоненты?

Beermonza 06.04.2009 15:55

Всегда нужно разрабатывать свой способ, в зависимости от требований. Все прочие готовые варианты - это ресурс тех самых игр. Лично для меня их применение у себя - кощунство.

IvaniuS 06.04.2009 16:03

у меня нет времени и возможностей(не ресурсов заметте) чтобы создавать собственные модели, текстуры, и пр. поэтому ищу альтернативный вариант знаний в рисовании и моделировании достаточно свои модели персонажей и текстуры давно внедрил и с радость смотрю в Лайнейдж 2, поэтому горю желанием даже от тудова использовать персонажей и текстуры.
к завершению поста скажу что в графиге не ГДИ а именно ДИКС вообще ноль только неделю что-то разбираюсь поэтому хочу и мотор внедрить Анриловский
Добвлю нашел заменю 3Д на гди т.к. у меня с геометрие й проблем нету вот пример системы координат для игры:
Код:

      /-------/
    /          /|   
  /          /  |
/--------/    /
|        |  /
|        | /
|-------|/

надеюсь понятно что это не внешняя а внутрення часть вот так можно реализовать 2д РПГ от 3-го лича:) или наклон в другую сторону

ВОПРОС: ЕСЛИ СОЗДАВАТЬ СВОЙ РЕДАКТОР С ОБЬЕКТАМИ БОЛЬШЕ ЧЕМ 10 ЧТО ДЕЛАТЬ ПЕРЕДХОДИТЬ к интегеру или стрингу хочу пейти к ини в нем записывать название обекта все координаты его создание и его размеры это можно сделать?

Beermonza 06.04.2009 16:21

Хорош флуд разводить :) ...тема не та, ...посмотри "Как вы относитесь к созданию игр на Delphi?", наша команда делает 2D в изометрии, выглядит тем же 3D, но камера не плавает. Этот пост не в тему последний.

Алекс Ялта 10.04.2009 20:38

Canvas тормозит или я?
 
Вложений: 1
Вроде бы ознакомился со всей информацией, что есть в нашем разделе. Но всё же решил переспросить. У меня в примере Tbitmap отрисовывается через буффер, но при быстром передвижении явно заметны мелькания изображения. Это означает, что я неправильно где-то отрисовываю или canvas даже через буффер так медленно работает?

Вот код отрисовки:
Код:

procedure TForm1.Timer1Timer(Sender: TObject);
begin

Buffer.Canvas.Rectangle(0,0,640,480);

ShipBuf.Canvas.CopyRect(bounds(0,0,64,64),ShipSprite.Canvas,bounds(k*64,str*64,64,64));


Buffer.Canvas.Draw(px,py,ShipBuf);

Form1.Canvas.Draw(0,0,Buffer);

вот сам пример:

Манжосов Денис :) 10.04.2009 21:03

А у меня ничего не тормозит.

Алекс Ялта 10.04.2009 21:08

Цитата:

Сообщение от Манжосов Денис :) (Сообщение 238790)
А у меня ничего не тормозит.

Я , наверное, неверно выразился. Происходит мелькание корабля при перемещении?

Манжосов Денис :) 10.04.2009 21:12

Нет, не происходит.

DeKot 10.04.2009 21:34

Цитата:

мелькание корабля при перемещении?
Еще от "железа" зависит- тактовая, а особенно память компа.

Алекс Ялта 10.04.2009 22:23

Странно, я явно вижу рывки при перемещении. У меня железо нормальное. Atlon 5.2, Video Radeon 3650, 3 Gb оперативной

Beermonza 11.04.2009 00:59

Алекс Ялта, у таймера какой интервал? ...извини, исходник не смотрел.

Алекс Ялта 11.04.2009 11:17

Таймер интервал в 1 мили секунду установлен

Beermonza 11.04.2009 14:47

Цитата:

Сообщение от Алекс Ялта (Сообщение 238779)
Вроде бы ознакомился со всей информацией, что есть в нашем разделе. Но всё же решил переспросить. У меня в примере Tbitmap отрисовывается через буффер, но при быстром передвижении явно заметны мелькания изображения. Это означает, что я неправильно где-то отрисовываю или canvas даже через буффер так медленно работает?

Вот код отрисовки:
Код:

procedure TForm1.Timer1Timer(Sender: TObject);
begin

Buffer.Canvas.Rectangle(0,0,640,480);

ShipBuf.Canvas.CopyRect(bounds(0,0,64,64),ShipSprite.Canvas,bounds(k*64,str*64,64,64));


Buffer.Canvas.Draw(px,py,ShipBuf);

Form1.Canvas.Draw(0,0,Buffer);


Скажи ка, сколько ты насчитал Canvas'ов в этом коде? ...я вижу 5, ...и при том, что интервал таймера 1 мс, не мудрено обнаружить мелькание, а загрузку процессора смотрел? (ты меня конечно извини, но EXE файлы я не запускаю, только после просмотра кода и самостоятельной компиляции, чего всем советую).
Давай вспомним сколько кадров достаточно для нормального восприятия движения объектов в 2D глазом человека. 24 кадра, но поставим умышленно 30 кадров. Поделим одну секунду на 30, получим приблизительно 33 мс (1000 мс / 30 кадров). ОС работает с графикой в форме сносно не быстрее чем 30 кадров в секунду, при больших изображениях, ...это проверено. Значит нужно ставить 33 мс интервал в таймере, а от лишних Canvas'ов нужно избавляться.

Алекс Ялта 12.04.2009 19:39

Вложений: 1
Загрузку процессора через диспетчер задач установить мне не удалось. Выдает при работе приложения 0-1% (Может из-за того, что процессор не слабый). Файл подкачки увеличивается на 3Мб.
Я пытался избавиться от мелькания путем установки интервала таймера в 33 Мс. Мелькание действительно исчезает, но при этом, соответственно, падает скорость перемещения объекта.
После, я выделил обработку перемещения объекта в отдельный таймер с интевалом в 1 Мс, а отрисовку оставил в первом таймере с интервалом в 33 Мс. Мелькания стали чуть менее заметны.
Выходит, что проблема может скрываться в черезмерном использовании canvasa? Но я не могу понять каким образом можно избавиться в том коде от лишних canvas? И какой из них является лишним? Вот весь исходник

Манжосов Денис :) 12.04.2009 19:55

У меня опять ничего не мелькает...
Я изменил вот это начальную строку в таймере
Код:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
Buffer.Canvas.FillRect(rect(0,0,640,480));

Хотя разницы особо нет

Манжосов Денис :) 12.04.2009 20:18

Хочу сделать игру с использованием WinAPI. Но не знаю ничего про вывод графики, если писать всё с нуля. Может кто-нибудь написать урок про вывод графики, используя WinAPI?
Заранее спасибо

Boris96_2007 12.04.2009 22:03

Цитата:

Сообщение от -=DeS=- (Сообщение 6708)
В этом уроке я научу вас как можно передвигать обьекты по форме с помощью клавиш...
--------------------------
Начнём.
1)Создайте новый проект File> New> Application
2)Теперь киньте на форму объект TShape
3)После этого выбираем в Object TreeView форму (Form1)
4)В Object inspector на вкладке Events ищем свойство OnKeyDown и щёлкаем на него 2 раза.
5)В созданной процедуре пишем код (я рекомендую вам не просто копировать а понять как это работает!)

Этот код будет двигат фигуру Shape1 на 2 пиксела вверх!
---------------------------
Попробуйте сами написать движение вниз, вправо, влево...
Позже и это будет показано!

Я не понял что такое Теперь киньте на форму объект TShape
Потом После этого выбираем в Object TreeView форму (Form1)
Ну и это 4)В Object inspector на вкладке Events ищем свойство OnKeyDown и щёлкаем на него 2 раза.
5)В созданной процедуре пишем код (я рекомендую вам не просто копировать а понять как это работает!)
расскажите что и куда кликать

Xzen 13.04.2009 07:52

Падскажити плиз как сделать чтоб объект не только ездил при нажатии кнопок но и поворачивался на N угол если к примеру зажать стрелку влево

Алекс Ялта 13.04.2009 09:45

Цитата:

Сообщение от Xzen (Сообщение 240144)
Падскажити плиз как сделать чтоб объект не только ездил при нажатии кнопок но и поворачивался на N угол если к примеру зажать стрелку влево

Если Вы новичек, то без сторонних библиотек (типа DelphiX) будет сложновато. Примеров на форуме полно
http://www.programmersforum.ru/searc...earchid=233664

Алекс Ялта 13.04.2009 13:24

Вложений: 1
Цитата:

Сообщение от Boris96_2007 (Сообщение 239976)
Я не понял что такое Теперь киньте на форму объект TShape
Потом После этого выбираем в Object TreeView форму (Form1)
Ну и это 4)В Object inspector на вкладке Events ищем свойство OnKeyDown и щёлкаем на него 2 раза.
5)В созданной процедуре пишем код (я рекомендую вам не просто копировать а понять как это работает!)
расскажите что и куда кликать

Объект TShape находится на закладке Additional палитры компонентов Delphi. На скрине, который прилагается, выделено красным.
Object TreeView находится по умолчанию в левом верхнем углу, под меню.
Object inspector располагается по умолчанию сразу под окошком Object TreeView (в левом нижнем углу).
Что и куда кликать уже рассказали, смотрите внимательно и кликайте)

Beermonza 13.04.2009 17:12

Вложений: 1
Алекс Ялта, посмотрел твой пример с космическим корабликом. Можно ускорить намного и сделать так, чтобы не было рывков при движении, ...но это уже тема не для новичков, там GDI и ассемблер.
Можно посоветовать хранить каждый кадр кораблика в отдельной ячейке массива типа TBitmap. Вот эта строчка будет ненужна:
Код:

ShipBuf.Canvas.CopyRect(bounds(0,0,64,64),ShipSprite.Canvas,bounds(k*64,str*64,64,64));
Сразу в буфер вместо:
Код:

Buffer.Canvas.Draw(px,py,ShipBuf);
Вот так:
Код:

Buffer.Canvas.Draw(px,py,ShipAnimMas[{код направления},{номер кадра}].Tex);
Вот картинку тебе кинул на задний фон.

Алекс Ялта 13.04.2009 18:27

Цитата:

Сообщение от Beermonza (Сообщение 240401)
Алекс Ялта, посмотрел твой пример с космическим корабликом. Можно ускорить намного и сделать так, чтобы не было рывков при движении, ...но это уже тема не для новичков, там GDI и ассемблер.
Можно посоветовать хранить каждый кадр кораблика в отдельной ячейке массива типа TBitmap. Вот эта строчка будет ненужна:
Код:

ShipBuf.Canvas.CopyRect(bounds(0,0,64,64),ShipSprite.Canvas,bounds(k*64,str*64,64,64));
Сразу в буфер вместо:
Код:

Buffer.Canvas.Draw(px,py,ShipBuf);
Вот так:
Код:

Buffer.Canvas.Draw(px,py,ShipAnimMas[{код направления},{номер кадра}].Tex);
Вот картинку тебе кинул на задний фон.

Спасибо за совет. Думаю, пора приступать к изучению WinApi, т.к. наконец то мне стало понятно, что есть медленный вывод графики и в чем он выражается)
P.S. На данный момент изучаю основы работы с сетью на компонентах ClientSocket - ServerSocket по Вашим примерам (http://pblog.ru/?p=91). Кстати, полезнее и доступнее пока примеров в инете не нашел. Так что и за это тоже спасибо)

Вадим Буренков 13.04.2009 18:38

Цитата:

P.S. На данный момент изучаю основы работы с сетью на компонентах ClientSocket - ServerSocket по Вашим примерам (http://pblog.ru/?p=91).
Интересно! Нужно будет как нибудь сделать какую-нибудь прстую игру по интернету.

oleg91 28.04.2009 17:36

Вот тут хороший исходник http://gigapeta.com/dl/196396ab01834. Показывает все основные методы программирования графики. И весит немного.

Gigabit 29.04.2009 22:44

Не могу понять что за ошибка
 
Вложений: 1
Решил написать свою первую игру, ближе к сердцу аркада.
Взял за образец Игру от Kostia,
пост № 106 (Огромное спасибо, надеюсь авторских прав не нарушил :d ) почитав здесь хорошенько, усложнил код:
Не могу продолжить из-за того что :
1 когда нажимаешь пробел много раз
2 когда нажимаешь пробел и Юнит бьется головой о потолок
Выходит ошибка:
Цитата:

First chance exception at $7C812A6B. Exception class EAccessViolation with message 'Access violation at address 00452BA0 in module 'Project1_2.exe'. Read of address 02CF9D50'. Process Project1_2.exe (3456)
Жму Break, Делфи остонавливается на строке Вывода изображения:
Код:

mapbmp.Canvas.draw(round(xp-20),round(yp-20),SpArr[UnitSplineN]);
вот исходный код:
Код:

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    AnimTimer: TTimer;
    procedure AnimTimerTimer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

const
  g=0.5; //ускорение свободного падения

var
  Form1: TForm1;
  map: array[1..40,1..35]of char; //карта
  mapbmp: tbitmap; //буфер
  sx,sy: real; //скорость по x и y
  xp,yp: real; //позиция игрока на экране(в пикселах)
  wall,Lu1,lu2,ru1,ru2:Tbitmap; //Текстуры
  leftU:boolean;
  Getunitstate:integer;
  Spline:Tbitmap;
  SpArr: array [1..256] of Tbitmap;
  UnitSplineN:integer;
implementation

{$R *.dfm}

function keypressed(key: byte): boolean;
var
  keys: TKeyboardState;
begin
  result:=false;
  GetKeyboardState(keys);
  if(keys[key]=128)or(keys[key]=129)then result:=true;
end;
procedure LoadTexture;
var i:integer;
begin
// n определяется сразу, если вы точно знаете сколько будет текстур
  for i:=1 to 15 do
    begin
      Spline:=TBitmap.Create;
      Spline.LoadFromFile(IntToStr(i)+'.bmp');
      SpArr[i]:=Spline;
    end;
end;

procedure loadlevel();
var
  f: TextFile;
  x,y: integer;
begin
  sx:=0; sy:=0;
  AssignFile(f,'level1.txt');
  Reset(f);
  for y:=1 to 35 do
    for x:=1 to 40 do
    begin
      if x<40 then
        read(f,map[x,y])
      else
        readln(f,map[x,y]);
      if map[x,y]='2'then
      begin
        xp:=x*20; yp:=y*20;
      end;
    end;
  CloseFile(f);
end;

procedure TForm1.AnimTimerTimer(Sender: TObject);
var n:integer;
begin
case GetUnitState of
0: n:=1;
1: n:=11;
2: n:=6;
3: ;
end;
  if UnitSplineN<n then
  UnitSplineN:=n;
  if UnitSplineN<n+4 then
  UnitSplineN:=UnitSplineN+1
  else UnitSplineN:=n;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
  LoadTexture;
  loadlevel;
  mapbmp:=TBitmap.Create;
  mapbmp.Width:=800;
  mapbmp.Height:=700;
  mapbmp.Canvas.Brush.Color:=clWhite;
  wall:=TBitmap.Create;
  wall.LoadFromFile('wall.bmp');
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  x,y: integer;
begin
 GetUnitState:=0;
  //если под ногами пусто, то падаем(проверяем 2 нижние точки(ноги))
  if (map[round(xp)div 20,round((yp+sy+20))div 20]<>'1')and
    (map[round(xp+19)div 20,round((yp+sy+20))div 20]<>'1') then
    sy:=sy+g
  else
  begin
    sy:=0;
    //прыжок
    if keypressed(32) then
    begin
      sy:=-8;   
      GetUnitState:=3;
    end;
  end;
  if keypressed(39) then
    begin
    sx:=1;
    GetUnitState:=1;
    end;
  if keypressed(37) then
    begin
    sx:=-1;
    GetUnitState:=2;
    end;
  //если головой ударились, то польше не летим ввер, а начинаем падать
  if (map[round(xp)div 20,round((yp+sy))div 20]='1')or
    (map[round(xp+19)div 20,round((yp+sy))div 20]='1')then
    sy:=0;
  //если слево или справо стена, то не идем на таран
  if (map[round(xp+sx)div 20,round(yp+sy)div 20]='1')or
    (map[round(xp+sx)div 20,round(yp+sy+18)div 20]='1')or
    (map[round(xp+sx+19)div 20,round(yp+sy)div 20]='1')or
    (map[round(xp+sx+19)div 20,round(yp+sy+19)div 20]='1')then
    sx:=0;

  xp:=xp+sx;
  yp:=yp+sy;

  sx:=0;

  //проверим, нашел игрок конец уровня или нет
  if map[round(xp+10)div 20,round(yp+10)div 20]='3'then loadlevel;
  mapbmp.Canvas.FillRect(Rect(0,0,20*40,20*35));
  mapbmp.Canvas.draw(round(xp-20),round(yp-20),SpArr[UnitSplineN]);
  for y:=1 to 35 do
    for x:=1 to 40 do
      case map[x,y] of
      '1': mapbmp.Canvas.draw(x*20-20,y*20-20,Wall);
      '3': mapbmp.Canvas.rectangle(x*20-16,y*20-16,x*20-6,y*20-6)
      end;
  form1.Canvas.Draw(0,0,mapbmp);
end;

end.

Оставляю игру+ эдитор.
P.S. Заранее спасибо.

Kostia 02.05.2009 17:36

Брр! Я сейчас и в своем коде не разберусь. Вы лучше начните проект заново. Писать не много и пользы больше!

А еще лучше, если вы в тетради изложите свои мысли в словесно-математичеко-формульной форме. У вас наверняка возникнут вопросы и вот их спросите на форуме, а когда закончите с тетрадью, переводите словесную-математическую-формульную форму на язык программирования.

Gigabit 03.05.2009 18:19

Спасибо вам Kostia за совет, в тетради всё действительно понятней.
Я исправил ошибку
Код:

    //прыжок
    if keypressed(32) then
    begin
      sy:=-8;   
      GetUnitState:=3;

Всё окозалось просто -
GetUnitState Параметр задавал тип анимации 3 (анимация прыжка) для юнита, но анимации этой я не сделал.
Код:

case GetUnitState of
0: n:=1;
1: n:=11;
2: n:=6;
3: ;

Если я правельно всё понял оператор Case из-за этого барахлил.
Цитата:

Вы лучше начните проект заново. Писать не много и пользы больше!
Я не хочу "Бросать", этот проект, уж больно он мне понравился.
Просто если я начну писать всё заново, то именно того что есть сейчас, я повторить не смогу.
А на сегодня у меня в игре есть Редактор карт, два Бонуса (скорость, прыжок), и два ... не знаю как назвать вообщем Шипы и анимираванный Огонь.

Вадим Буренков 21.05.2009 16:19

Цитата:

Алекс Ялта, посмотрел твой пример с космическим корабликом. Можно ускорить намного и сделать так, чтобы не было рывков при движении, ...но это уже тема не для новичков, там GDI и ассемблер.
Beermonza, расскажи пожалуйста. Очень нужно.

Beermonza 21.05.2009 16:41

Вадим Буренков, в теме "Как Вы относитесь к созданию игр на Delphi?" с поста #46 читай подряд, найдешь создание буферов, отрисовку, перебрасывание подложки в кадр, и много интересного и поучительного.
Здесь описывать не буду, да и не имею право, ...тема не та, чтобы такие сложность показывать.

Вадим Буренков 21.05.2009 17:31

Я там найду как выводить графику на Canvas без тормозов и ряби?А то мне не хочется убивать весь вечер на чтение 265 топиков и так ничего не добиться.
Проблема в том, что в Canvas меня устраивает все, кроме скорости вывода графики.Я использую два буфера и это дает результат, но не достаточный.

Beermonza 21.05.2009 19:31

Цитата:

Сообщение от Вадим Буренков (Сообщение 269385)
Я там найду как выводить графику на Canvas без тормозов и ряби?

Ты там найдешь как создать буфер кадра таким способом, что с ним можно будет работать как в Canvas, так и отрисовывать быстрым методом через указатель в ОЗУ с использованием вставки на ассемблере при поддержке MMX процессора.
В общем флуд тут не разводим (в данной теме это все флуд), все вопросы по этому поводу в соответствующей теме "Как вы относитесь к созданию игр на Delphi?", там опиши свою ситуацию, что отрисовываешь и как, постараюсь помочь.

AvaMight 19.06.2009 18:56

Года 2 назад изучал Delphi (Имею так сказать базовые знания (циклы процедуры и т.д )) .Случайно зашел на форум, прочитал тему от начала до конца и заинтересовался этим делом:) Скачал программу из поста №106.

Посидел пару-тройку часов(а могет и больше :p:p) поразбирался во всем этом( должен заметить где-то на 90% алгоритмы, функции , логика оказались не понятными).Сидел разбирался до тех пор пока не написал комментарий почти к каждой строке (спасибо Google за помощь).В итоге с n-ой попытки смог осознанно воспроизвести где то 95% кода.

Решил что пожалуй можно чуть чуть потренироватся в расширении данной программы( так сказать для закрепления знаний). Увеличил размер карты, количество текстур( и тому подобная мелочь).Написал код все заработало но....

Но Написать заного то что уже видел раньше(хоть и осознанно) легче чем написать свое:)

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

Kostia 19.06.2009 19:04

Выкладывай наработки, глянем что там "творится".

AvaMight 19.06.2009 19:15

Вложений: 1
Вот .

Единственно я изменил размер клетки на 20. Может поэтому и такие проблемы( хотя картинки тоже сделал 20х20)

Карта примитивная просто для проверки)

Kostia 19.06.2009 19:23

Так и думал, а кто будет менять размеры самих массивов? А лучше сделать все это дело динамическим!
В общем блокнот кажет, что в нем размер карты 52*21, а массив:
Код:

map: array[1..50,1..20] of char;
...
For y:=1 to 21 do
      For x:=1 to 52  do
...

AvaMight, если хочешь добиться динамики, то лучше воспользоваться динамическими массивами или списками(TList).

AvaMight 19.06.2009 20:43

В общем с этим вроде как разабрался( проблема была в самой карте(я ее 51х21 сделал) + я написал <=50 в процедуре loadlvl) что и привело к появлению 2 лишних клеток по Х.



p/s Пользоваться Tlist не хочу ибо в данной теме не нашел не 1 его применение(вроде читал внимательно) а без примеров сам многое не сделаю.
Использование динамических массивов даже не представляю как тут реализовать))) ( все же я еще не достаточно силен в программировании, может как наберусь опыта буду использовать)

Пока буду пользоваться таким методом(все таки были приложены усилия в его освоении, и теперь на что то переключится на другое обидно)))

p/p/s Да и спасибо за быстрый и понятный ответ))

Beermonza 19.06.2009 21:57

AvaMight, всегда в карте первыми байтами идет размер карты, при считывании с файла, размеры записываются в переменные, которые используются в циклах, ...никаких ошибок в кодах не будет, разумеется, если массив предусматривает все размеры карт, можно динамикой не пользоваться, но по-уму стоит пользовать динамический массив.

Лубышев 21.06.2009 19:50

Проблема:
Решил добавить звуки в игру. (Ну например звук выстрела по нажатию) Пробовал стандартными средствами – не получается :(
Хотел использовать PlaySound но звуки воспроизводятся не моментально и игра подвисает пака не пройдет звук.
Хотел использовать поток для этого, опять не то.
Какие есть решения?
1.Нужно чтобы звуки моментально воспроизводились
2.Нужно чтобы игра при этом не подвисала
3.Нужно чтобы звук воспроизводился неоднократно, т.е. если выстрелил и пока еще шел звук, если еще раз выстрелил еще раз воспроизвелся.
4.А вообще было бы шикарно, если бы одновременно с этим играла бы музыка и, если бы поразил выстрелом врага он бы тоже издал какой-нибудь звук.

Манжосов Денис :) 21.06.2009 19:57

PlaySound('Sound.wav', 0, SND_ASYNC);
Так всё происходит синхронно с программой. Можно, наверное, использовать также FMOD(про него в теме: "Моя первая аркада на Delphi. Демка")

Лубышев 22.06.2009 00:31

Замечательно, хотя что то все же не так... немного притормаживает.Стандартные альтернативы есть?
А как сделать чтобы одновременно несколько звуков воспроизводилось? например все это происходит на фоне музыки?

Манжосов Денис :) 22.06.2009 08:49

Я этого не знаю, но делаю по другому. Через mediaplayer играет фоновая музыка, а через PlaySound уже отдельные звуки.

Лубышев 22.06.2009 10:28

Я тоже так же хотел сделать... Но если целый ряд звуков надо воспроизводить то не целый же ряд MP делать...
(Играет музыка, раздаются выстрелы, если попал то враг стонет, кричит и тому подобное..., раздаются прочие технические звуки)

Arigato 22.06.2009 19:06

В DelphiX есть компонент, SoundList, кажется. Так вот с его помощью можно проигрывать несколько звуков сразу.

Beermonza 22.06.2009 19:55

Да, в DelphiX есть два компонента, обертка для DirectX. Движок - DXSound, и архив DXWaveList. Можно использовать формат .dxw, ...что это я к сожалению не в курсе, а вот вавчики работают как надо.

Вадим Буренков 22.06.2009 21:06

Я предлагаю свой простой вариант проигрывания звуков одновременно и без тормозов:
(пост №20)

Alex2009 22.06.2009 21:18

С мгоей точки зрения лутше использовать GL scene

Манжосов Денис :) 24.06.2009 11:05

Проиграть два звука одновременно
Код:

uses

MMSystem;

procedure SendMCICommand(Cmd: string);
var
RetVal: Integer;
ErrMsg: array[0..254] of char;
begin
RetVal := mciSendString(PChar(Cmd), nil, 0, 0);
if RetVal <> 0 then
begin
  {get message for returned value}
  mciGetErrorString(RetVal, ErrMsg, 255);
  MessageDlg(StrPas(ErrMsg), mtError, [mbOK], 0);
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
SendMCICommand('open waveaudio shareable');
SendMCICommand('play "C:\xyz\BackgroundMusic.wav"');
SendMCICommand('play "C:\xyz\AnotherMusic.wav"');
SendMCICommand('close waveaudio');

end;

Использован материал Delphi Russian Knowledge Base from Vit

sasha1993 27.06.2009 19:39

спасибо за уроки!

sasha1993 27.06.2009 22:59

воттакая вот цетата:
На самом деле всё оказалось проще чем я думал. Нужно создать дополнительный буффер, в котором задается прозрачность и её цвет. В этот буффер отрисовывается кадр, а буффер рисуется в основной буффер программы.



если у когото есть время покажите пожалуйста как этот буфер с невидемостью сделать.

Shadow_1329 28.06.2009 08:20

Tank.Transparent:=true - где танк это твой игровой объект. Это делает вокруг танка фон прозрачным. У имиджа точно также, только вместо Tank - Image1. Буффер делаешь так:


Код:

Buffer:Tbitmap;//создаешь переменную

//в созданий формы пишешь
Buffer:=Tbitmap.Create;
//зАтем в Таймере пишешь
Buffer.Canvas.Draw(0,0,Fone)// где фон- это игровой фон.Это нужно писать сначала, если не хочешь чтобы фон рисовался на персонаже.
Buffer.Canvas.Draw(x,y,Tank)//где танк твой игровой обьект. Персонаж рисуется на фоне.
Form1.Canvas.Draw(0,0,Buffer);//Выводим буфер на форму и все!


Вот возникла проблема. У меня есть здание которое не умещается в одну клетку карты(100 на 100). Когда я прохожу перед ним то у меня персонаж рисуется на переднем плане а здание на втором. Но мне нужнно пройти за ним, и для этого нужно чтобы здание было на переднем плане а перс за ним рисовался и его скрывало зданием. Как это реализовать?

Arigato 28.06.2009 09:15

Сначала рисуйте персонажа, а затем - здание.

DeKot 28.06.2009 09:19

На буфере последовательно рисуем фон, персонаж,здание и выводим этот бутерброд на форму.
Arigato быстрей оказался.

Shadow_1329 28.06.2009 09:40

Ну это то я знаю. Но вопрос в другом. Как сделать так чтобы в некоторых случаях персонаж скрывался зданием?

Arigato 28.06.2009 10:12

Цитата:

Как сделать так чтобы в некоторых случаях персонаж скрывался зданием?
Именно на этот вопрос Вам и дали ответ выше.

Kostia 28.06.2009 13:45

Цитата:

1 Вариант:
Идешь от дальних к ближним по горизонтальным рядам.
В каждом горизонтальном ряду рисуешь по слоям от нижнего до верхнего.

2 Вариант:
Сперва отрисовываешь весь ландшафт (при условии, что скалы, которые что-то загораживают, считаются объектами, а не элементами ландшафта).
Все объекты в изложенном в п.1 порядке.

3 Вариант:
Делаешь много слоев: по глубине и по высоте. Располагаешь их в следующем порядке:
- дальний нижний, дальний повыше, ... дальний верхний... средний нижний... средний верхний... ближний нижний... ближний верхний.
Рендеришь от начала к концу.

4 Вариант:
рендеришь послойно, в каждом слое от дальнего к ближнему.

5 Вариант - аналогичен 3, но порядок такой:
-дальний нижний, поближе нижний,...ближайший нижний, дальний повыше... ближний повыше... ближний верхний.

Вот 5 разных реализации отображения по слоям, приведи хотя бы одну ошибку хоты бы в одном варианте.
http://www.gamedev.ru/code/forum/?id=78629

sasha1993 28.06.2009 15:00

спасибо за буфер! очень поиогло!

Beermonza 28.06.2009 15:16

Есть способ еще проще, ...следишь не за координатами объектов в массиве объектов, а проверяешь карту по ячейкам, от левой верхней, до правой нижней, т.е. за фрагментом карты, которая влезла в экран. Далее, значит перебирая ячейки карты смотришь запись "объект", там указан индекс на массив объектов в игре, по этому индексу отрисовываешь объект на карте, в текущей ячейке. Здания - если они крупнее, у них есть смещение спрайта, стоять они будут в конкретной ячейке карты но за счет смещения, их клетка будет в центре самого здания. Как движущийся объект не будет передвигаться, отображение всегда будет верным. Но нужно иметь в виду, что вокруг клетки здания нужно ввести "мертвую зону" в аккурат по периметру видимого силуэта (в изометрии по основанию).

sasha1993 28.06.2009 20:47

Я нашол много хороших примеров движения перса за мышкой, но как можно научить его обходить преграды?

Есть идеи?

Beermonza 28.06.2009 21:56

Все азы и примеры в этой теме, ...тебе нужно конкретно? ...читай тему: http://programmersforum.ru/showthread.php?t=50504

AvaMight 29.06.2009 17:40

Скинте пожалуйста кто то код простейшего редактора карт.( потихоньку пишу игру но карты надоело в блокноте рисовать :) )

Kostia 29.06.2009 17:55

http://programmersforum.ru/showthread.php?t=53491

AvaMight 29.06.2009 19:32

Извеняюсь там только exe файл.Мне же нужен сам код если не сложно. Хотелось бы разобратся с самим механизмом создания редакторов.

Alex2009 29.06.2009 23:42

Прошу помощи.Подскажите хороший движок для игры DelphiX GLScene и OpenGl не предлогать.Чуть незабыл 3д движок

Kostia 30.06.2009 08:33

http://programmersforum.ru/showthread.php?t=46225

Выбирай...

Alex2009 01.07.2009 17:11

У меня вопрос как пользоватся GLScriptLibrary можно статью какую небуть или код.
С уважением Alex2009

sasha1993 02.07.2009 19:55

у меня при написании кода


for i1:=1 to 500 do
for i2:=1 to 500 do
begin
map[i1,i2].pict:=Tbitmap.Create;
map[i1,i2].pict.width:=35;
map[i1,i2].pict.height:=35;
map[i1,i2].pict.LoadFromFile('1.bmp');
form1.Canvas.Draw(i1*35-35,i2*35-35,map[i1,i2].pict);
end;


возникает ошыбка 'неверний деструктор' что это значит и как этого избежать

Beermonza 03.07.2009 00:00

Умножь 500 на 35, получишь недопустимый размер буфера канвы и по длине и по ширине. Отталкивайся от математики, дели разрешение экрана на твои 35 и получай истинный предел цикла по i1 и i2.

Не засоряем тему мелкими вопросами, создавайте отдельные темы, ...эта тема для разбора фундаментальных приемов построения игр.

profi 07.07.2009 19:08

Думаю в этой теме не будет лишней книга по программированию стратегических игр с DX9

Dj_smart 17.07.2009 15:52

Alex2009, покопай в сторону DGLEngine.

sasha1993 22.07.2009 23:58

Подскажите пожалуйста как можно вывести полосу жизней над персонажем,единственное что мне пришло в голову рисовать через канву , но это не очень удобно. Есть другие идеи?

Beermonza 23.07.2009 00:42

Если элементарно совсем делать, то стоит просто один раз подрисовать полоску в кадры анимации над персонажем, и выводить как всегда без лишних действий иначе, постоянная прорисовка загрузит машину без надобности. Только когда нужно изменить количество жизни - выводить процедуру перерисовки полоски, также на все кадры один раз.

Вадим Буренков 23.07.2009 11:05

Игровое окно с изменяющимися размерами.
 
Вложений: 1
Понял интересную вещь. Даже в играх на канвасе можно сделать игровое окно с изменяющимися размерами (как в OpenGL), например как на скриншоте.
Вместо вывода подготовленного буффера на форму процедурой:
Код:

MainForm.Canvas.Draw(0,0,Buffer);
нужно копировать изображение коммандой:
Код:

MainForm.Canvas.CopyRect(bounds(0,0,MainForm.ClientWidth,MainForm.ClientHeight),Buffer.Canvas,bounds(0,0,640,480));
Буффер будет растягиваться на размер окна.
Единственная проблема это потеря качества :( .

mutabor 23.07.2009 13:49

Можно, но это немного не то. Там меняется разрешение экрана, если полноэкранный режим, а если в окне то я не встречал чтобы можно было растягивать. Кстати рисуя на канве тоже можно разрешение экрана менять, одно другого не касается.

p.s. Более красиво масштабирует StretchBlt из WinApi. Но это все более актуально для GUI прикладных программ, а не для игр. Для игр видеокарта есть, имхо. Хотя сам я на канве делал игры, но пригодились эти навыки именно в прикладных программах, с этими знаниями у вас развязаны руки в плане интерфейса.

0nni 24.07.2009 00:04

StretchBlt еще хорошо с SetStretchBltMode() использовать, в режиме HALFTONE, картинка будет сглаживаться при масштабировании.

Вадим Буренков 24.07.2009 09:59

Цитата:

StretchBlt еще хорошо с SetStretchBltMode() использовать, в режиме HALFTONE, картинка будет сглаживаться при масштабировании.
Действительно картинка теперь не зернистая и без квадратов, +1. HALFTONE добавляет сглаживание, только чем больше растянуто окно тем больше тормозит.

VintProg 24.07.2009 14:27

Вадим Буренков
А сама игра на OpenGl или DirectX?

mutabor 25.07.2009 01:41

Цитата:

Сообщение от VintProg (Сообщение 314330)
Вадим Буренков
А сама игра на OpenGl или DirectX?

Лучше! На CanvAS )))

FLASH-KILLER 30.07.2009 18:58

как это потом перевести во swf и с помощью чего помогите пожалуйста.знаю что так делают но не знаю как это сделать

FLASH-KILLER 30.07.2009 19:03

Вадим Буренков есть программа в интернете что бы улучшать картинки поищи .я если вспомню сайт то тебе скину

FLASH-KILLER 30.07.2009 20:48

-=DeS=- у меня вопрос где находится обьект TShape

Beermonza 30.07.2009 21:24

Вкладка Additional, 7-й по счету.
Вообще с подобными вопросами впредь в раздел "Общие вопросы Delphi".

-COREY- 04.08.2009 14:42

Народ,помогите плиз.На странице 9 этой темы был выложен исходник хода коня для шахмат.Начал разбирать его.Там есть такой код.
Код:

.........
function Cell2X(Cell: byte): byte;
begin
Result:=Cell mod 8;
end;
далее


function TForm1.DestCheck(x,y: byte): boolean;
var
TmpCell: byte;
dx, dy: byte;
begin
Result:=False;
TmpCell:=Coord2Cell(x,y);
dx:=Abs(x-Cell2X(StartCell));
dy:=Abs(y-Cell2Y(StartCell));
if (TmpCell <> StartCell) then
  if ((dx = 2) and (dy = 1)) or
    ((dx = 1) and (dy = 2)) then
    begin
    if dx = 2 then
      begin
        if (x > Cell2X(StartCell)) then
          stepX:=LongStep
        else
          stepX:=0-LongStep;
        if y > Cell2Y(StartCell) then
          stepY:=ShortStep
        else
          stepY:=0-ShortStep;
      end
    else
      begin
        if (x > Cell2X(StartCell)) then
          stepX:=ShortStep
        else
          stepX:=0-ShortStep;
        if y > Cell2Y(StartCell) then
          stepY:=LongStep
        else
          stepY:=0-LongStep;
      end;
    Result:=True;
    end;
end;

StartCell была описана ранее типом shortint и ей присвоено значение -1
Код:

...........
var
  StartCell: shortint = -1;
...........

Но при этом она вводится в функцию в которую должна вводиться переменная типа byte.Byte же не может быть отрицательным.Исходник работает как надо.Объясните,пожалуйста,почему так.

Shadow_1329 04.08.2009 16:34

Почему это не может быть отрицательным?

-COREY- 04.08.2009 17:23

ну насколько я помню диапазон чисел типа byte 0..255.Да и в учебнике так написано.

Dj_smart 04.08.2009 17:45

Ну про крайней мере будет перебор и ты получишь число 255 (256 + (-1)) помоему :) Возможно на это авторы и расчитывают.

Shadow_1329 04.08.2009 17:47

А помоему там сказано что -255 - +255

-COREY- 10.08.2009 18:40

нет,точно от 0 до 255.Это и у Сухарева и у Культина в учебниках

Beermonza 10.08.2009 20:16

Числовые переменные типа Integer, Word или ShortInt и Byte можно приравнивать друг к другу, только вот если будет нарушен диапазон например Byte (0 - 255), то значения будут вырезаться относительно битов. Если приравнять числу типа Byte переменную типа ShortInt значение которой минус один (-1) то значение переменной типа Byte будет 255.
Так же все эти переменные переводятся в строковый тип одной и той же функцией IntToStr();
Смотреть нужно внимательно, и не допускать прохождения в код вычислений некорректных присвоений, ...только в условиях, как флаги, и то, спорный момент.

Beermonza 12.08.2009 23:23

Соблюдайте правила
 
Убедительная просьба ко всем создающим здесь сообщения, пожалуйста не задавайте мелкие вопросы общего характера "как нажать кнопку", "не могу запустить код", "как заставить панель двигаться по экрану", "как вывести в Image картинку из файла" и пр. Для этого есть раздел "Общие вопросы Delphi". Если ваше сообщение касается игр, и есть частный вопрос, создавайте новую тему. Здесь же задаются глобальные вопросы, вопросы по уже имеющимся урокам, размещаются статьи и уроки касающиеся создания игр простыми способами, или способами средней сложности.

L_M 16.09.2009 16:10

Кто-нибудь может написать о создании сетевой игры небольшой урок(для Дельфи, не браузерную)? Какие компоненты использовать для содинения лучше(ведь их много, многие разделены на 2 части - клиент и сервер, как организовать перебор адресов/портов), как организовать ходы лучше(например нужно ли создавать объекты для других игроков или ограничиться изменением картинки и параметров), как будут соотноситься компьютерные противники(монстры) и персонажи(вероятно на сервере должны ходить монстры), как организовать сервер(например можно на простом хостинге создать демон-скрипт, который будет раздавать информацию клиентам, или в любом экземпляре программы лучше создавать сервер, к которому напрямую будут подключаться желающие, или есть постоянный хостинг(про хостинг я говорю как про бесплатную, хоть и ограниченную возможность создать игровой сервер) на который будут поступать запросы клинтов о подключении/создании экземпляра игры(карты), а он будет только рассылать информацию клинтам о друг друге(ип и порты), чтобы программа потом сама соединялась)? В общем какие-то основы расскажите. Уф-ф-ф. Вроде написал. Понимаю, что читать сложно, поэтому ввел начертание.

p.s. если что, за грамматику извините. Предупреждаю сразу))

Beermonza 25.09.2009 15:36

L_M, разбор создания сетевых игр уже противоречит названию этой темы, т.е. не для новичка это дело.

VintProg 26.09.2009 11:36

L_M
Создавай новую тему в таком случае.

Ckomoroh 25.10.2009 23:29

Я хочу сделать игру типа "танчики", для двоих человек, перемещение танков я могу сделать...а вот как сделать стены комнаты...предположим они будут картинками, но стен много, а значит много и картинок, а проверять на столкновение каждую стену - это как-то муторно...

Подскажите пожалуйста.Заранее благодарен.

P.S.
И еще хотелось бы узнать, как сделать так чтобы картинка пули постоянно создавалась....т.е. существует 1 объект - пуля, а как сделать так, чтобы могла вылетать несколько пуль одновременно?

Kostia 25.10.2009 23:36

Самый подходящий для этого случая вариант, это использовать перемещение танков не по пикселям, а по клеточкам. Читай выше, здесь это уже обсуждалось!

Вадим Буренков 25.10.2009 23:41

Цитата:

а вот как сделать стены комнаты...предположим они будут картинками, но стен много, а значит много и картинок, а проверять на столкновение каждую стену - это как-то муторно...
Ну назвать это муторным неправильно. Так и должно быть: например сначала проверяются столкновения двух танков, потом первого танка со всеми стенами и второго танка со всеми стенами. OOП сильно облегчает задачу.
Цитата:

т.е. существует 1 объект - пуля, а как сделать так, чтобы могла вылетать несколько пуль одновременно?
То же самое с пулями - создать тип пули TBullet и процедуры для работы с ним (выстрел, удаление, прорисовка, проверка попадания). Все пули хранить в массиве и в таймере проверять каждую пулю массива на столкновение.

Beermonza 26.10.2009 16:16

Цитата:

Сообщение от Вадим Буренков (Сообщение 372831)
Ну назвать это муторным неправильно. Так и должно быть: например сначала проверяются столкновения двух танков, потом первого танка со всеми стенами и второго танка со всеми стенами. OOП сильно облегчает задачу.

Есть еще один способ - обрабатывая игровые объекты по списку смотреть их окружение на карте по клеточкам вокруг, и в зависимости от препятствий принимать решения. Ресурсов столько же, но цикл один.

russian-stalker 26.10.2009 17:14

Как пример:
Код:

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Timer1Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  tbullet=class
    x,y:integer;
    force:array[0..1] of integer;
    procedure update;
  end;

var
  Form1: TForm1;
  l:tlist;

implementation

{$R *.dfm}

{ tbullet }

procedure tbullet.update;
begin
x:=x+force[0];
y:=y+force[1];
form1.Canvas.MoveTo(x,y);
form1.Canvas.LineTo(x+40,y+40);
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
b:tbullet;
begin
b:=tbullet.Create;
b.x:=x;
b.y:=y;
b.force[0]:=-40;
b.force[1]:=-40;
l.Add(b);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
i:integer;
b:tbullet;
begin
Canvas.Rectangle(0,0,width,height);
if l.Count>0 then
for i:=0 to l.Count-1 do
begin
b:=l.Items[i];
b.update;
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
l:=tlist.Create;
timer1.Interval:=50;
end;

end.


Манжосов Денис :) 26.11.2009 17:34

Решил перевести систему координат в своём игровом проекте, и возникла куча вопросов. У каждого объекта есть координата (50*m; 50*n), где m и n - элементы массива. Массив динамический: matrix: array of array of smallint;
В-общем, не стоит говорить и спрашивать насчёт этой системы хранения карты, отрисовки на экран и создания "подложки" (Спасибо, Beermonza, метод всё-таки действительно помог). Поговорим о новом способе.
Итак. Теперь карта (лучше говорить матрица) объектов представляет из себя такую структуру:
Код:

type
  TMatrix = record
    Position: TPoint; // Координаты объекта
    ObjectType: smallint; // Тип объекта (1 - дерево, 2 - камень, 3 - цветок ...)
  end;
var
  matrix: array of array of TMatrix; // Двумерный динамический массив карты

И вот здесь начинаются трудности. Во первых, как рисовать всё это на экран, ведь координаты могу быть такими (135000; 10). Я думаю, что можно пользоваться какими-то формулами, которые переведут координаты для отрисовки... Второе, как хранить все координаты в файле. Вот так:
Код:

for i := 0 to LengthX do  // Длина массива
 for j := 0 to LengthY do
  Writeln(F, Matrix[i,j].TypeObject, Matrix[i,j].Position.X, Matrix[i,j].Position.Y);

?
Если вы располагаете информацией насчёт этого, напишите пожалуйста в этой теме подробный ответ, буду очень благодарен. Спасибо.

Beermonza 26.11.2009 18:05

Все станет ясно, если вспомнить что карта - матрица. Что есть в матрице? ...ячейки. Что есть ячейка? ...элементарная запись некоторого кода, или индекс на банк ресурсов. Например карта - матрица типа Byte, на каждую клетку приходится 1 байт данный, или индекса, ...т.е. закодирован 1 из 256 возможных объектов. В матрице есть столбец и строка. Допустим, карта имеет размер 100х100 клеток. Здесь видно координаты объекта? ...видно, т.к. мы точно знаем какого размера элементарный тайл клетки карты. Нужно всего лишь умножить порядковые номера в столбце и в строке на высоту и ширину текстуры тайла карты. Что и применил Манжосов Денис
Цитата:

У каждого объекта есть координата (50*m; 50*n)
Сохранять такую матрицу элементарно просто - подряд в одну строку. У нас есть цикл типа (в сообщении выше):
Цитата:

for i := 0 to LengthX do
for j := 0 to LengthY do
...достаточно записывать один единственный индекс объекта из диапазона 0 - 255 командой Write. Как потом считывать с файла? ...нужно предусмотреть запись при сохранении размеров, в виде 2 байт данных: "Длина" "Ширина" "блок данных...."

Это все сохраняется в формате File Of Byte. При считывании мы точно знаем, что первые два байта - это размеры карты, применим эти данные к циклу считывания как его границы. Так же просто в цикле считаем данные посредством команды Read, она не привязана к размерам матрицы и будет при каждом шаге цикла брать следующий байт в файле.

Что получается. Карта есть, считывание есть, ...нужен банк текстур и система их правильного использования. Нет ничего проще. Создаем систему каталогов. Называем ее как нам нужно, один из каталогов - каталог текстур, в нем 256 файлов, которые так и носят имя в виде цифр. Вместе с ними идут допустим текстовые txt или ini файлы с данными, как правильно пользоваться текстурой, с тем же именем.
Что происходит? ...при считывании карты с файла, и взяв индекс объекта, мы точно знаем как он называется, и где лежат его ресурсы. Код выдергивает с каталога все данные по имени файлов и загружает их в одномерный массив банка текстур, в первую свободную ячейку. Разумеется тип банка текстур нужно создать, чтобы в нем были все данные для обработки и отрисовки. Как только ресурс загружен, в массиве карты, вместо индекса объекта записывается номер ячейки в банке текстур. Зачем это делается? ...если в карте есть одинаковые объекты, то код найдет этот ресурс в банке и укажет просто номер ячейки, не загружая ресурсы снова. Т.е. идет ссылка на один и тот же объект в разных местах карты.

Если есть вопросы с плавающей камерой относительно большой карты, или если объектов в игре более чем 256, задавайте вопросы, ...отвечу по мере поступления.

Манжосов Денис :) 26.11.2009 18:19

Размер карты 100х100 пикселей вы имели ввиду? И каждый элемент массива (100х100) несёт в себе значение каждого пикселя? Или я не так понял. Дело в том, что столбов нет никаких, то есть объект можно поставить в абсолютно любую клетку (317; 526); (465; 777). Вот в чём проблема, и я не знаю как это реализовать. Надеюсь, мы поняли друг друга, Beermonza? Что именно вы имеете ввиду?

Вадим Буренков 26.11.2009 18:29

Цитата:

Размер карты 100х100 пикселей вы имели ввиду?
Как я понимаю карту лучше измерять в ячейках. Каждая ячейка занимает определенное кол-во пикселей (это константа).И каждый элемент массива (100х100) несёт в себе значение (код или название) определенного объекта в игре. Например 1 - дерево, 2 - дом и.т.д.
Цитата:

то есть объект можно поставить в абсолютно любую клетку (317; 526);
Никаких проблем нет, просто ставим в значение элемента матрицы необходимый код объекта. Процедура рисования по коду определяет изображение и рисует его в координатах этой ячейки.Как вычислить координату ячейки ты уже привел.
Как подвинуть камеру? - просто вычитаем из полученной координаты объекта координату камеры.

Манжосов Денис :) 26.11.2009 18:33

(130.000; 0) - а что с такой координатой делать или даже если ещё больше значение будет? Использовать тип для координат LongInt просто? А если вообще не записывать объекты все подряд, а только те, которые есть на карте?
Ну, у меня сейчас вот так отрисовывается:
Код:

begin
  _2DEraseBuffer;
  _2DDraw(0,0,bg);
  Player.Animation[CurAnim].DrawAnimation(Player.Position.X,
                                        Player.Position.Y); // Рисуем анимацию игрока
  Inc(Player.Animation[CurAnim].FrameNumber); // Увеличиваем кадр анимации
  Collisions; // Коллизии
  _2DDrawScreen(0,100,Canvas);
end;

А вот создание подложки...
Код:

procedure TMainForm.CreateBG;
var
  i,j: byte;
begin
  bg.Canvas.FillRect(Rect(0,0,800,400));
  for i := 0 to MapResX do
  for j := 0 to MapResY do
    if Map.ObjMatrix[i + Map.sx, j + Map.sy] <> - 1 then
      bg.Canvas.Draw(i * sPoint, j * sPoint,
                    GameObjects[Map.ObjMatrix[i + Map.sx,j + Map.sy]].Bitmap);
end;


Вадим Буренков 26.11.2009 18:52

Цитата:

(130.000; 0) - а что с такой координатой делать или даже если ещё больше значение будет?
Ты какую игру делаешь?Вспомни какие размеры карты в героиIII.Мне кажется там нет карт 130000 на 13000 ячеек!!!

Манжосов Денис :) 26.11.2009 18:59

Так...Внимательно почитай мой пост первый, когда я только спросил как реализовать систему хранения файла отличную от моей в старой игре! Вот тип
Код:

type
  TMatrix = record
    PosX, PosY: longint;
    TypeObject: byte;
  end;

Видишь? Отлично! PosX = 130.000 по X, по Y - 0! Массив:
Код:

matrix: array of TMatrix;
Каждый раз, как добавляем объект на карту увеличиваем длину массива на 1! Вот про такую систему я говорю.
Блин, я от ответов только путаюсь сильней :)
И как мне сделать игровую камеру, чтобы она рисовала объекты от начала экрана?

Beermonza 26.11.2009 19:06

Я же напечатал:
Цитата:

Допустим, карта имеет размер 100х100 клеток
Не совсем понимаю, что требуется получить?

Карта не измеряется в экранных пикселях, ...клетка - это типичное название элементарной поверхности в игре. В математическом виде, клетка - одна ячейка матрицы, у которой есть координата i и j, номера i в матрице располагаются по столбцам, j - по строкам. Пример, вот карта игры 7х7:

j,i 1 2 3 4 5 6 7
1 0 0 0 0 0 0 0
2 0 3 0 0 0 0 0
3 0 0 0 0 0 0 0
4 0 0 0 2 0 0 0
5 0 0 0 0 0 0 0
6 0 1 0 0 0 0 0
7 0 0 0 0 0 9 0

...так выглядит математическая модель карты. А вот так она записана в файле, теоретически:

770000000030000000000000002000000000001000000000090

...разумеется в файле в виде символов кодовой страницы.
Если у вас размер тайла (одной элементарной клетки, ее текстуры) 50х50 пикселей на экране, то полная графическая поверхность будет 350х350 пикселей.

Вот так хранить карту довольно рационально. Почему столько нулей и зачем их хранить? ...вспомним, что поверхность просто усеяна текстурами, и причем разными, ...записать пропуск проще, чем строить систему списка, к тому же она не сожмется потом, а последовательный массив сожмется, и довольно прилично.

Манжосов Денис :) 26.11.2009 19:11

Beermonza, Вадим, вы мне говорите, о том, о чём я уже знаю. У меня всё это в игре реализовано. Вопрос был в другом, ну да ладно, буду сам находить ответ. Спасибо.

Beermonza 26.11.2009 19:13

Цитата:

(130000; 0) - а что с такой координатой делать или даже если ещё больше значение будет?
Рискну предположить, что на экран такое по любому не влезет, это фрагмент карты, начиная с клетки по-Х: 130000 и на размер экрана. Если тайл 50х50, сколько клеток влезает на экран 1024 по-горизонтали? ...21 клетка. Значит на экране показан фрагмент карты с по-Х: 130000 до 130021. Вот и рисуем в цикле по диапазону StartX to StartX+ScreenLenX, т.е. 21-у клетку в 50х50 пикселей каждая. Это систем плавающей камеры, спрашивал, нужно ли объяснять.

apromix 27.11.2009 13:56

Цитата:

Сообщение от Манжосов Денис :) (Сообщение 399711)
Решил перевести систему координат в своём игровом проекте, и возникла куча вопросов. У каждого объекта есть координата (50*m; 50*n), где m и n - элементы массива. Массив динамический: matrix: array of array of smallint;
В-общем, не стоит говорить и спрашивать насчёт этой системы хранения карты, отрисовки на экран и создания "подложки" (Спасибо, Beermonza, метод всё-таки действительно помог). Поговорим о новом способе.
Итак. Теперь карта (лучше говорить матрица) объектов представляет из себя такую структуру:
Код:

type
  TMatrix = record
    Position: TPoint; // Координаты объекта
    ObjectType: smallint; // Тип объекта (1 - дерево, 2 - камень, 3 - цветок ...)
  end;
var
  matrix: array of array of TMatrix; // Двумерный динамический массив карты

И вот здесь начинаются трудности. Во первых, как рисовать всё это на экран, ведь координаты могу быть такими (135000; 10). Я думаю, что можно пользоваться какими-то формулами, которые переведут координаты для отрисовки... Второе, как хранить все координаты в файле. Вот так:
Код:

for i := 0 to LengthX do  // Длина массива
 for j := 0 to LengthY do
  Writeln(F, Matrix[i,j].TypeObject, Matrix[i,j].Position.X, Matrix[i,j].Position.Y);

?
Если вы располагаете информацией насчёт этого, напишите пожалуйста в этой теме подробный ответ, буду очень благодарен. Спасибо.

Слишком просто для игры на такой большой карте. Вот моя структура из моего проекта (rpg):

Код:

type
  TMapCell = record
    Tile      : Integer;
    Index    : Integer;
    ID        : Integer;
    SKeySchema: Integer;
    Count    : Integer;
    IsVisible : Boolean;
  end;

  TMap = record
    Cells: array[1..MAP_WIDTH,1..MAP_HEIGHT] of TMapCell;
    LocalMapLeft, LocalMapTop: Integer;
  end;

  TMapCity = array[0..AddMapWidth, 0..AddMapWidth] of TMapCell;

  TGameMap = array[1..MaxDungeonLevel] of TMap;

  TDesk=array [0..LOCAL_MAP_WIDTH,0..LOCAL_MAP_HEIGHT] of Integer;

И сохраняется все это, как сейв, со структурой, в обычный текстовый файл :)

Beermonza 27.11.2009 15:13

Мы все говорим об одной и той же математической модели карты - матрице. Но, математическая матрица содержит в своих ячейках по определению числа - в данном случае индексы. Так намного проще обращаться к одним и тем же объектам, и записывать в файл только эти индексы, или по иному - код объекта, однобайтный или составной.
Размер файла уменьшается в разы, ...кроме того мы экономим ОЗУ, храня каждый объект в единственном экземпляре. Если потребуется изменить объект "на лету", то достаточно сменить его ресурс в банке, один раз, не бегая по карте и не меняя его во всех клетках карты, где он находится.

Манжосов Денис :) 27.11.2009 15:27

В моём проекте есть массив двумерный x на y. Ячейка несёт в себе значение текстуры, которую нужно вывести на экран. Есть массив текстур:
Код:

TGameObject = record
  Blocked: integer; // Препятствие ли объект
  Bitmap: TBitmap; // Картинка объекта
  ... // ещё несколько параметров
end;
GameObjects: array [1..n] of TGameObject;

Вообще, я уже забил на систему, где объекты могут располагаться в любой части карты, в любой координаты.
Beermonza, а как у Вас в игре хранится файл карты? Объекты можно ставить, где угодно или есть наименьший размер ячейки, к примеру 10?

Beermonza 27.11.2009 15:54

Цитата:

Сообщение от Манжосов Денис :) (Сообщение 400405)
Вообще, я уже забил на систему, где объекты могут располагаться в любой части карты, в любой координаты.

Смутно представляю, что это были за планы, но замечу, что какую бы вы не взяли 2D игру, относительно древнюю или не очень, стратегию или РПГ, то заметите, что, например, отряд юнитов кучкуется не хаотично, а занимает определенно равномерно пространство, так, что можно заметить элементарные клетки, на которые поделена карта. Здания занимают несколько клеток по осям X и Y, т.е. площадь. Деревья растут либо кучкой по несколько, занимая несколько клеток, либо по одиночке. Куда бы не послали юнита, он остановится не на конкретном объекте, а перед ним, в пустой клетке и начнет действовать.
Так что, я думаю, то что предложено выше в полной мере позволяет реализовать любую 2D игру, и не только.
Цитата:

Сообщение от Манжосов Денис :) (Сообщение 400405)
Beermonza, а как у Вас в игре хранится файл карты? Объекты можно ставить, где угодно или есть наименьший размер ячейки, к примеру 10?

Размер клетки карты известен, это изометрический тайл, 2:1, он достаточно мал в игровом масштабе, кроме того, есть промежуточные клетки карты, так, что самых маленьких персонажей можно набить на карту как сардины в банку. Появляться объекты будут в клетках карты, по формуле w*j-sw, h*i-sh, где: w,h - размеры тайла, j,i - координаты клетки, sw,sh - статические смещения текстуры (центрирование).
Сохранение карты идет последовательно, клетка за клеткой, записывая код объекта, ...там где нет объектов идет пропусковый байт. После записи файл сжимается и записывается уже на винт.

Вадим Буренков 27.11.2009 16:07

Цитата:

Размер файла уменьшается в разы, ...кроме того мы экономим ОЗУ, храня каждый объект в единственном экземпляре. Если потребуется изменить объект "на лету", то достаточно сменить его ресурс в банке, один раз, не бегая по карте и не меняя его во всех клетках карты, где он находится.
Или можно использовать указатели. Загружается текстура, она распологается в памяти а на нее создается указатель. Гогда загружается новая текстура проверяется, была ли она загружена. Если да, то новыя память под нее не выделяется, а просто создается указатель под ранее загруженную текстуру, а если нет то она загружается полностью. С такой системой сколько бы одинаковых текстур ты загрузить не пытался, в памяти будет одна, а все переменные будут указателями (так сделано в любом нормальном движке).

apromix 27.11.2009 18:11

Вот почитал уроки. У меня все спрайты в отдельных файлах, решил их объединить в несколько, по темам. Возник вопрос: как загруженный битмап порезать? Может быть есть готовое решение?

Вадим Буренков 27.11.2009 18:23

Цитата:

как загруженный битмап порезать?
Можно копировать кусок спрайта в другой битмап: Frame.Canvas.CopyRect.

Манжосов Денис :) 27.11.2009 18:25

Код:

  TAnimation = object
    Enabled: boolean;
    AnimationFile, AnimationFrame: TBitmap;
    XResolution, YResolution: integer;
    MaxFrameCount: integer;
    FrameNumber: integer;

    procedure CreateAnimation(FileName: string; Max: integer; XRes, YRes: integer);
    procedure DrawAnimation(XPos, YPos: integer);
    procedure FreeAnimation;

  end;

Это тип "Анимация".
Код:

procedure TAnimation.CreateAnimation(FileName: string; Max: integer; XRes, YRes: integer);
var
  Root: string;
begin
  Root := ExtractFilePath(ParamStr(0));
  if not FileExists(Root + FileName) then exit;
  AnimationFile := TBitmap.Create;
  AnimationFile.LoadFromFile(FileName);

  AnimationFrame := TBitmap.Create;
  AnimationFrame.TransparentColor := AnimationFile.Canvas.Pixels[3,1];
  AnimationFrame.Transparent := true;

  XResolution := XRes;
  YResolution := YRes;

  AnimationFrame.Width := XResolution;
  AnimationFrame.Height := YResolution;

  MaxFrameCount := Max;
end;

А вот деление кадра на кусочки, точнее определение длины кусочка. Можно ещё не задавать размер кадра, а высчитывать его по формуле Количество Кадров разделить на Длину Битмапа.
Код:

procedure TAnimation.DrawAnimation(XPos, YPos: integer);
var
  XR, YR: integer;
begin
  AnimationFrame.Canvas.FillRect(AnimationFrame.Canvas.ClipRect);

  XR := XResolution * FrameNumber;
  YR := YResolution;

  AnimationFrame.Canvas.CopyRect(Bounds(0,0, XResolution, YResolution),
                                AnimationFile.Canvas,
                                Bounds(XR, 0, XResolution, YR));

  _2DDraw(XPos, YPos, AnimationFrame); // Рисовать на канвасе
  if FrameNumber = MaxFrameCount then FrameNumber := 0
end;

Вот так на экран выводить

Гром 27.11.2009 18:51

На самом деле здесь по-прежнему присутствует упомянутая некогда в топике проблема: если два объекта имеют одну и ту же анимацию, то они рисуются абсолютно синхронно, даже если по идее не должны (пример с поваленными деревьями).
Я недавно тоже столкнулся с этой проблемой и вначале измышлял совершенно дикие варианты вплоть до хранения в объекте текущего кадра анимации и количества кадров, и, соответственно проверкой на последний кадр вне функций самой анимации.
Вскоре, однако, нашел довольно изящное решение. Анимация по-прежнему хранится отдельно, текущий кадр хранится в объекте карты (без этого никуда), процедура рисования анимации принимает текущий кадр в качестве аргумента (в итоге на карте могут быть несколько объектов с одной и той же анимацией на разных стадиях) и, что самое главное - номер кадра передается функции рисования анимации по ссылке (пишу на C++). Т.о. проверка на последний кадр происходит не выходя за пределы типа анимации, а объект карты должен хранить всего лишь номер текущего кадра и не заботиться о том, является ли он последним.
Модификация кода по сравнению с вариантом, где текущий кадр хранился в типе анимации минимальна - удалил из типа переменную CurrFrame, вписав его вместо этого в качестве аргумента.
Не знаю, есть ли в Delphi ссылки, но, думаю, если что, можно воспользоваться указателями.

Beermonza 27.11.2009 19:09

Гром, именно этот тип анимации я описывал в качестве урока, ...кадр текущий и их макс. число хранит в себе каждый объект, а анимация одна в банке на все кадры. Это очень правильно и рационально.

Гром 27.11.2009 19:33

Beermonza, честно говоря, тему я почти не читал, т.к. дельфийский код читаю медленно на основе полузабытого паскаля и билдера... А вначале там и вовсе коды во вложенных файлах, их вообще лень читать...)
А как насчет хранения максимального номера кадра в типе анимации? По-моему, производить проверку номера кадров лучше всего прямо во время рисования кадра, т.е. в функции объекта типа анимация. Мне это кажется как-то более логично. К тому же, объект может иметь несколько различных видов анимации (например, дерево стоящее и дерево падающее). Если стоящее дерево имеет всего один кадр (или просто другое число кадров, нежели падающее), то как хранить число кадров? Отдельно для каждого типа анимации?
Вообще прямо сейчас я имею на руках работающий код рисования анимации, реализованный по этому методу, а вот до использования этой самой анимации в объектах еще не дошел, так что пока не знаю наиболее рациональных приемов.

Вадим Буренков 27.11.2009 20:18

Цитата:

А как насчет хранения максимального номера кадра в типе анимации? По-моему, производить проверку номера кадров лучше всего прямо во время рисования кадра, т.е. в функции объекта типа анимация. Мне это каже................
Все о чем ты говоришь есть в моем последнем примере.

Beermonza 27.11.2009 21:00

Товарищи, не меряемся длинной портянки кода, ...тема обязывает давать понятия новичкам.
Гром, условие на переполнение кадра (счетчик) использует оба значения, текущий кадр и макс. кадр, и переводит текущий на начальный, посему оба значения нужно хранить вместе (условно):

Код:

Inc(Obj[i,j].Frame);
If Obj[i,j].Frame > Obj[i,j].MaxFrame then Obj[i,j].Frame := 0;


Гром 27.11.2009 21:14

Beermonza, тоже логично...
С другой стороны, текущий кадр относится исключительно к конкретному объекту, а общее число кадров - ко всем объектам, использующим данную анимацию. Опять же и хранить идентичную информацию (число кадров) в каждом объекте - это, конечно, не так затратно, как своя собственная копия всей анимации для каждого объекта, но все же...
А если все же объект использует разные виды анимации? Например, какой-нибудь персонаж идет вправо, влево, вверх, вниз, по диагонали, в каждом из направлений машет мечом да плюс еще пьет зелья и леший знает что еще... И таких на карте много... Информация множится со страшной скоростью, тем более что и хранить неудобно, разве что в безликом массиве, когда не всегда понятно, какой номер элемента за какую анимацию отвечает.

apromix 27.11.2009 21:38

Цитата:

...тема обязывает давать понятия новичкам.
Вот вдохновили вы своей темой - решил сделать простенькую rogue-like игру, но по вашим советам, на спрайтах, но чтобы не мигало, как обычно бывает. С чего следует начать в описании структур?

Beermonza 27.11.2009 21:47

Открою небольшой секрет, которого быть может новички не знают, или слышали мельком, ...дело в том, что на одной общей текстуре могут быть расположены несколько типов анимации, относящиеся к одному типу объекта. В этом случае, один из объектов игры может пользоваться своим куском анимации "от сих до сих", макс. кадр у объектов может быть разный. Вот условно пример сборной текстуры:

ПП1 ... ПП8 ПЛ1 ... ПЛ8 ПВ1 ... ПВ8 ПН1 ... ПН8
АП1 ... АП8 АЛ1 ... АЛ8 АВ1 ... АВ8 АН1 ... АН8
ГП1 ... ГП8 ГЛ1 ... ГЛ8 ГВ1 ... ГВ8 ГН1 ... ГН8


Поясню что это за запись. Это представление сборной текстуры в виде структуры кусочков, кадров, по типу анимации.
Первая линия - подряд идущие кадры с 1 по 8 в разных, допустим 4-й направлениях. ПП - перемещение право, ПЛ - перемещение влево, ПВ - перемещение вверх, ПН - перемещение вниз.
Вторая линейка - атака, также по направлениям, третья - гибель по направлениям. Все это в одном графическом файле, с именем типа анимации. Когда объект использует анимацию, у него есть движковые переменные направления анимации 1, 2, 3, 4, но в анимации для универсальности используется общий счет текстур (у дерева нет направлений), поэтому объект, в данном случае персонаж, берет с банка текстуру тем же способом, что и все объекты, но использует исходя и игрового типа свой участок. Один персонаж идет с 1-го по 8-й кадр сборной текстуры, а второй с 9-го по 16-й, у них разный макс. кадр, и кроме того и начало, ...в данном случае условие If Obj[i,j].Frame > Obj[i,j].MaxFrame then Obj[i,j].Frame := 0; уже будет некорректным, вместо Obj[i,j].Frame := 0; будет Obj[i,j].Frame := Obj[i,j].StartFrame;

Гром 27.11.2009 22:01

Beermonza, ну да, в принципе про хранение всей анимации в одном файле слышал. Вплоть до хранения всех картинок небольшой игры в одной картинке.
При таком раскладе, действительно, использование анимации становится специфичным для конкретного объекта... Структура хранения информации, правда, усложняется...

Beermonza 27.11.2009 22:15

Кроме того, все манипуляции с анимацией вы должны вложить в сопровождающем файле особого типа, где расписано: какого размера кадр, сколько кадров всего, сколько типов находятся в сборе, как пользоваться вырезкой, по типам, направлениям и пр. пр. пр. ...в этом случае вы уже не лезете в код движка, а создаете сборную текстуру и файл параметров, ...движок сам применит анимацию как положено, притом по одному и тому же алгоритму, читая сопроводительный файл один раз при загрузке ресурса в банк текстур и анимаций.
Еще один момент, ...знаете чем анимация отличается от статической текстуры в данной структуре хранения? ...ничем, просто в файле написано что кадр всего 1 и тип один. Для движка не составит никакого труда лишний раз просчитать условие на 1 кадр, это рациональнее записи условий на наличие анимации.

Гром 27.11.2009 22:43

Да, насчет статичной картинки в один кадр я не то в этой теме, не то в соседней уже прочитал и реализовал!:)
Информацию по числу и размерам кадров хранить и использовать несложно... А вот куда писать информацию по типам, направлениям и пр? К анимации или объектам? Может быть, отдельно хранить собственно картинки, а отдельно - информацию о расположении анимации данного типа на ней? А потом объект обращается к конкретной структуре информации...
Как-то все-таки проще кажется хранить раздельно разные типы анимации (можно и для каждой анимации своя картинка), и уж потом обращаться к каждой из них в различных ситуациях... А уж разобрать хранящуюся на диске картинку хоть со всей анимацией игры на различные объекты анимации - не проблема...)

P.S.Хотя может и не проще это... Мозги нынче уже плохо соображают, завтра на свежую голову еще подумаю!:)

Beermonza 28.11.2009 21:14

Хозяин - Барин, ...кому как удобно, тот так и делает. Но в основе всегда - рациональное использование пространства дисков, оперативное использование ресурсов без вмешательства в код движка, создание структуры кода и распределение ресурсов для быстрого доступа/обработки.
Как ни крути, кроме самого движка тянется еще цепочка спец-программ для создания ресурсов, кроме, собственно, еще и редактора карт.

KIZ 29.11.2009 13:51

Цитата:

Сообщение от mutabor (Сообщение 89343)
Один из вариантов как можно сделать игру пазл.
Исходник с комментариями, читайте там.
Версия 0.1 (работает еще не все)
В следующей доделаю, а еще в следующей глянец наведу.

Больше не появилось никакой версии?

Skynet91 03.01.2010 17:06

Как сделать так чтоб игра показывалась на весь экран ну как обычные игры?? Заранее спасибо

p.s. Посоветуйте литературу по написании игр в Delphi??

Alex Cones 03.01.2010 17:39

Цитата:

весь экран
FormStyle =alwaysontop, + maximize.

Вадим Буренков 03.01.2010 18:23

Цитата:

p.s. Посоветуйте литературу по написании игр в Delphi??
Вряд-ли такие есть. Но вся необходимая информация есть на форумах. А если имеешь в виду графику то книг завались.

Skynet91 03.01.2010 20:03

Цитата:

Сообщение от Alex Cones (Сообщение 429678)
FormStyle =alwaysontop, + maximize.

Извините конечно но на каком это языке написано?

Alex Cones 03.01.2010 21:32

На русском матерном\схематичном.
Код:

Form1.FormStyle:=fsAlwaysOnTop;
Form1.BorderStyle:=bsNone;
Form1.WindowsState:=wsMaximized;


Ckomoroh 16.01.2010 17:30

Как сделать так, чтобы камера следовала за персонажем? то есть если сама карта 100х100, а видно только 20х15?
Я уже пытался сделать с помощью полной перерисовки экрана, т.е. при нажатии кнопки все видимые элементы сдвигаются в противоположную сторону, что дает эффект хождения, но при этом способе комп жутко тормозит=(...да и косяки там у меня жесткие...=)

Слушал, что можно сделать это с помощью регионов...
Кому не сложно подскажите...

apromix 16.01.2010 17:44

Нужно вырезать и отображать только часть мира размером в экран, остальное опускать и не обрабатывать.

Beermonza 18.01.2010 17:17

Ckomoroh, если у вас 100х100 весь уровень, а нужен кусочек, ...то при создании экранного фрагмента примените плавающий цикл. Создайте переменную StartX и StartY. Вот примерно так будет выглядеть выборка в общем массиве карты:

Код:

For Y := StartY to StartY + ScrHeight do
  Begin
    For X := StartX to StartX+ScrWidth do
      Begin
        {процедуры обработка клеток по-X и по-Y}
      end;
  end;

StartX и StartY - динамические переменные, они изменяются при переходе персонажа по клеткам, кроме того, при загрузке можно поставить сразу начало выборки.
ScrHeight и ScrWidth - размер экрана в клетках, который виден, т.е. диапазон по-X и по-Y от начала выборки до конца одного экрана.
Нужно предусмотреть так же момент, когда персонаж у правого края карты, параметры StartX, StartY, ScrHeight и ScrWidth остаются статичными, только сам персонаж меняет смое положение.

fenix-elite 01.02.2010 07:32

Щас делаю игру-аркаду, взял как пример исходник Beermonza, сделал проверку столкновений, управление и т.д. У меня все движение в одном таймере обрабатывается, ия не могу сделать прыжок. Нужно что бы по нажатию по W значению speedy придавалось значение 10, а потом пока снизу нет припятствия герой падал вниз. т.е sy постепенно уменьшалась, и становилась отрицательной пока герой не упадет на что нибудь )) Как это реализовать я знаю, но вот проблема если жать клавишу W и не отпускать, то SY всегда будет придаваться значение 10, т.е тело всегд будет лететь вверх :eek:. Управление реализовано с помощью флагов, тот же самый Beermonza, выкладывал реализацию.. :confused:

Deamonig 01.02.2010 08:37

ну движение объекта вверх, а потом внизу можно реализовать таким образом:
Код:

if (getkeystate(ord('W') and 128)=128) or (Up<>0) then
  begin
  if Up=0 then
    begin
    Yp:=Y;  // с какой точки пригнул
    Up:=1;  // обозначаем что он пригнул
    end;
  if Y>500  then  // подпригнет до точки 500
    Y:=Y-10
  else
    Up:=2;
  if Up=2 then
    if Y<Yp      // пока не призмелится
    then Y:=Y+10
    else
        begin
        Y:=Yp;
        Up:=0;
        end; 
  end;


fenix-elite 01.02.2010 09:43

Если я правильно этот код понял, то он мне не подойдет, т.к я могу прыгнуть с одной высоты, и он должен будет падать до столкновения с непроходимой клеткой....Мне просто нужно при нажатии на кнопку W совершить прыжок, и до окончания прыжка обрабатывать нажата ли клавиши не надо.. Но дело в том что все обрабатывается в таймере, т.е он все равно каждый такт будет проверять нажата ли клавиша, и как я уже писал герой пока нажата клавиша будет лететь вверх, либо упираться в максимальную высоту прыжка и зависать там пока не отпушу клавишу.... Может есть еще какие то варианты?

Swarog 01.02.2010 11:48

А ты предыдущий пример пробовал, он подходит под все твои требования, в нем проверяется в каком состоянии сейчас персонаж и прыжок осуществляется только в том случаи если он не в прыжке.

Deamonig 01.02.2010 12:29

Попробую обьяснить. Тебе достаточно ввести одну переменную в твой код, которая будет хранить информацию о состоянии игрока (0 - стоит на земле, 1 - летит вверх, 2 - летит вниз). И осуществлять новый прижок только если он стоит, т. е. переменная равна нулю. Если не понятно, приведи пример своего кода, в котором обрабатывается прижок. Помогу исправить

Beermonza 01.02.2010 16:16

Пример аркады с прыжком
 
Вложений: 1
Вот пример с прыжками, в комментариях. Пример на двух пользователей, на WASD и стрелках. Размер текстуры - цветных квадратов, берется автоматически. Пример совсем сырой и довольно древний, кому нужно, тот переделает, ...но есть в нем механизмы уже "взрослой" аркады, т.е. собственные типы на карту и игрока, ...отрисовка силами Canvas и BitBlt.

fenix-elite 01.02.2010 19:07

Спасибо за примеры, щас буду пробывать их приделать для себя. Позже отпишу что вышло =)

fenix-elite 01.02.2010 19:39

Beermonza, Вобщем если я правильно понял ваш алгоритм, то там при нажатии на W прыжку присваивается true. Потом в таймере проверяется клетка "под ногами", если там 0 то скорость падения каждый такт увеличивается на g, а если 1 то скорость 0, и клетка после падения поднимается на указанную величину( вот этот момент немного не понял ). и проверяется значение Jump, если да то скорость падения уменьшили. Я ничего не упустил? =)

Beermonza 01.02.2010 22:12

Да, ..в условии проверка на "пол под ногами", если оно ложное, т.е. под ногами пол, то скорость становится отрицательной, каждый такт уменьшаясь на гравитацию G. В какой-то момент условие это становится истинным, т.е. под ногами нет пола, и происходит дальнейшее уменьшение скорости, пока она не переползет за 0 и не отправит объект обратно к полу со скоростью, постоянно увеличивающуюся на гравитацию G. Как только пол достигнут, условие снова становится ложным, и проверяет флаг прыжка, если его нет, то скорость будет равна нулю, т.е. объект неподвижен, стоит на полу.
Есть еще проверка на "потолок". Это условие ищет столкновение сверху, если находит непроходимую клетку, то устанавливает скорость положительную, объект летит вниз. Через какое-то время условие становится ложным, а проверка на "пол под ногами" истинным, и объект падает вниз.

fenix-elite 02.02.2010 10:01

А про смещения можешь поподробнее рассказать, потому как постоянно возникают такие ситуации когда объект проваливается..

Beermonza 02.02.2010 15:18

Объект может провалиться только если встретится с другим, поскольку они оба меняют под себя проходимость, а проверки на их взаимодействие просто нет.
Вот этот код показывает, что происходит на карте, как меняются координаты объектов:
Код:

// отрисовка точных координат в массиве карты (не обязательное и бессовестное)
BitBuf.Canvas.Draw(UPosX*cell, UPosY*cell, UTexPos);

Для чего вообще нужно так делать? ...для того чтобы уйти от привязки к пикселям монитора, и считать в привычной системе карты, т.е. ее клетками. В любой момент можно создать объект в нужном месте карты. Притом, система не привязана к размеру тайлов, она универсальна.
Чтобы избавиться от рывков, нужно ввести смещение по осям X и Y. Эти смещения отсчитываются до поры, пока не нужно будет перейти на соседнюю клетку. Большая текстура показывает плавность хода, благодаря смещениям.

Pyton 09.02.2010 20:40

Вопрос: как лучше делать меню и интерфейс игры в целом?
То есть использовать для каждого окна свою форму, например для меню-форма №1, для главного окна игры - форма №2, для опций - форму №3 и т.д. или уничтожать и создавать кнопки на одной форме?

Гром 09.02.2010 21:58

Если в плане именно лучше, то на мой субъективный взгляд вообще меню, опции и подобные вещи кнопок содержать не должны (имеются в виду кнопки разряда TButton и им подобные). Лучше если все такие объекты будут нарисованы.
Вот как лично я реализовал в своей игре меню. Для обычного, собственно игрового, режима в игре есть свой буфер типа TBitmap, куда рисуется вся визуальная часть, ну а потом это дело копируется на канвас формы. Для меню также создается свой объект типа TBitmap, залитый каким-нибудь ядовитым цветом. На нем имеется несколько изображений неправильной формы, представляющие собой "кнопки" меню. Фон у них того же ядовитого цвета. Фон меню у меня рисовался в обычном буфере, игровом, выводился на форму, поверх него - с помощью функции Draw выводился битмап меню с установленным TransparentColor значением того самого ядовитого цвета. Как отлавливалось взаимодействие с меню: при вождении мышкой по форме считываются координаты курсора, по щелчку - проверяем цвет пикселя на битмапе меню с координатами последней позиции курсора. Если не цвет прозрачности - с помощью простых вычислений находим, какая это была кнопка. Впрочем, у меня еще было своеобразное подсвечивание каждой кнопки при наведении, что несколько усложняло весь алгоритм.
Из альтернативных способов реализации подобного поведения меню - вместо битмапа меню используется форма, тоже прозрачная, синхронно двигающаяся с главной формой. При щелчке по прозрачной части второй формы клик должен прийтись по нижней форме. После попыток воплотить этот вариант я отказался от него по следующим причинам: во-первых, мой C++ Builder отказался считать щелчки по прозрачной части формы щелчками по нижней (главной) форме (в Delphi, однако, говорят, этот прием работает); во-вторых, вторая форма, в положении StayOnTop делается сама "активной", хоть и невидима со своими границами, а главная - соответственно подсвечивалась как "неактивная"; в-третьих, синхронное перемещение стало проблемой, т.к. происходило по таймеру, и даже при интервале 1мс вторая форма заметно запаздывала, получалось меню висящее вообще вне окна игры! Да и вообще, я спервоначалу намучался, когда выбирал правильный способ работы со второй формой, так что не захотел дальше с ней работать. Ну и еще из причин - зачем создавать лишнюю форму, когда можно ограничиться всего лишь битмапом, подумал я.
И, собственно, еще один, более простой, но неплохо смотрящийся вариант. Опять же, меню рисуется каким-то фоновым рисунком, кнопки представляются красиво нарисованными правильными прямоугольниками и располагаются как вам надо. Все меню рисуется в одном (том же игровом) буфере, координаты точки, где произошел клик, однозначно сопоставляются с нужной кнопкой с помощью простейших расчетов.
Вот такое мое видение способов рисования меню. Единственное, что я молчаливо здесь предполагаю - это что меню имеет свой собственный фон, т.е. не рисуется поверх игрового процесса (впрочем, с помощью способа, который выбрал себе я, и это можно, только и тут будут свои ограничения).

Beermonza 10.02.2010 19:27

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

1. На основе форм (TForm)

Под каждую группу элементов интерфейса создается отдельная форма. В ней расположены элементы декора (Image) и элементы управления, всевозможные кнопки, переключатели, полоски состояния и пр. Если стандартные компоненты не устраивают, то все можно выполнить с помощью Image, помещая в них графические экземпляры кнопок не стандартной формы. В OnClick выполняется обработка нажатия на такую "нарисованную" кнопку. Кроме того, можно воспользоваться событиями Image - OnMouseDown и OnMouseUp, в первом событии можно смещать Image по Top и Left на 1 пиксел, во втором возвращать на место, ...при этом будет иллюзия притапливания рисованной кнопки в момент нажатия на клавишу мыши и возвращение при отпускании. Процедура с OnClick теперь переползет в OnMouseUp, и OnClick уже не нужно. В Image вас будет интересовать свойство Transparent. Гром, пожаловался на свой C++ Builder, но я вам говорю со 100-процентной гарантией, если часть прозрачная, то никакие клики мыши на ней в Delphi 7 не проходят по прозрачной форме, если за ней есть главная, ...т.е. работает только по видимой части рисованной кнопки на форме меню, прозрачные части графики считаются не активными, поскольку и форма и ее компоненты для ОС - суть, графика, и все состояния прозрачности компонентов подчиняются основным настройкам форм.
Если не устраивает стандартный стиль окна, то он убирается совсем, по свойству BorderStyle = bsNone, НО! ...не забудьте про отдельную кнопку закрытия формы, иначе она так и будет маячить на экране. Синхронизация понадобится, если игра выполнена в окне, это делается по таймеру с интервалом 31 мс (даже есть некая иллюзия 3D). В таймере условие на проверку положения главной формы, со старым положением и новым, если есть отличие, узнаем на сколько и двигаем все формы интерфейса на столько же.

2. На основе панелей (TPanel)

Вы точно знаете, что у вас квадратные не прозрачные элементы меню/интерфейса, с графическим задним фоном. В этом случае все меню создаются на панелях, на задний фон помещаются Image, на передний - стандартные компоненты, или рисованные, или те же Panel в виде кнопок, их цвет можно менять. Все элементы готовые располагаются в сторонке скрытыми "по-умолчанию" (Visible = False), выставляются на места после запуска программы, появляются и исчезают по созданной структуре меню и интерфейса. Вся графика загружается только после запуска программы. Этот метод сокращает размер исполнительного файла и загружает CPU значительно меньше.

3. На основе буферов TBitmap и "пустых" Image в качестве зон срабатывания

Этот метод позволяет создавать меню любой графической сложности, и накладывать его поверх изображения главной формы. Несколько пустых Image с заданными размерами (несколько меньшими чем границы рисунка, ибо кнопка рисуется на единственной главной форме, ее прозрачные части тоже будут активными на клик). В соответствии со структурой меню/интерфейса на главную форму накладываются разные буфера TBitmap, и активные области Image "плавают" по форме как-угодно.

4. Полностью графический метод, без VCL
В основе PNG-фрагменты форм, из которых с помощью конструктора собирается скелет любой формы, или готовые изображения форм хранятся в сжатом виде и подгружаются в буфера. Области срабатывания хранятся в движке интерфейса, который отслеживает положение курсора мыши на главной форме. Посредством флагов определяется нужно ли выполнять отслеживание нажатий или нет, на каждый конкретный объект меню/интерфейса. Здесь повсеместно вспомогательные файлы структуры меню, особого типа.

Выбирайте.

Alex Cones 10.02.2010 19:35

Цитата:

Выбирайте.
Дополню один маленький пунктик, собственного (уже отточенного) изготовления. На форму меню помещается один TImage, который накрывает всю форму, на нем отрисовывается TBitMap фона, На OnMove TImag`а навешена проверка координат типа:
Код:

If (X>5) And (X<45) And (Y>5) And (Y<45) Then Image1.Canvas.Draw(5,5,LightButton) Else ...
на остальные кнопки стоит аналогичная проверка. Если же ни одно условие не сработало, переходим по последнему Else и рисуем фон (который затрет предыдущие кнопки). На OnMouseDown навешены аналогичные проверки с той разницей, что еще выполнится процедура. Проверено - ни малейшего подрагивания или мерцания, даже если очень быстро дергать мышью.

Вот мой пример (на форум не влезло)

Beermonza 10.02.2010 21:39

Alex Cones, это пункт 4:
Цитата:

Сообщение от Beermonza
Области срабатывания хранятся в движке интерфейса, который отслеживает положение курсора мыши на главной форме

...но, с отличием, извиняюсь, в худшую сторону, ...почему? ...OnMove - вещь неблагодарная если в ней столько условий, ...движение мышью будет сопровождаться повышением нагрузки на CPU. Разумный вариант для OnMove - это только считывание координат в клиентской части формы:

Код:

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  MouseX := X;
  MouseY := Y;
end;

MouseX, MouseY - координаты курсора на форме, их использовать нужно на OnMouseDown и OnMouseUp, там и будут условия на диапазоны.
Кроме того, если есть движок, то проект серьезный, а ему не с руки сходить на Canvas и TBitmap. Ежели хочется именно так, то почему бы и нет, ...но с головой применять методы, иначе складывается ложно представление о силе Delphi в игростроении без библиотек и движков.

Pyton 18.02.2010 17:41

Вопрос наверняка уже был раньше: как сделать перемещение вражеских существ с течением времени? Для этого необходимо в таймере написать приращение скорости для существа?

Alex Cones 18.02.2010 17:48

Цитата:

написать приращение скорости для существа?
Учите физику - это будет ускорение. Приращение к координатам - будет перемещение.

Pyton 18.02.2010 23:10

Я имею ввиду, что существо движется от одной точки к другой, например, только по оси абсцисс. Оно движется с определенной скоростью. Для него надо создавать отдельный таймер, писать в главном таймере или еще как-то по-другому?

Гром 18.02.2010 23:21

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

Beermonza 19.02.2010 00:14

Управление, прямо говоря, мобом осуществляется набором условий, по имеющемуся набору параметров в его типе, минимум таких как: текущие координаты, координаты перемещения, скорость движения, состояние.
Как ими пользоваться? ...разбираем. Вот стоит на карте моб. У него есть запись текущих координат, ...с позиционированием все понятно. Теперь его состояние, ...допустим он находится в ожидании на кого напасть, но вокруг никого нет (алгоритм поиска цели вокруг себя на некоторый радиус). Вот в один из тактов алгоритм бота под порядковым номером в списке "нащупал" на карте цель (допустим вас, ...определил по типу объекта), алгоритм поиска цели указывает координаты перемещения, т.е. куда должен топать моб, и задает скорость, в зависимости от типа моба. Проходя через общую для всех структуру перемещения, координатам моба начисляются смещения, равные скорости перемещения, и будут начисляться до той поры, пока эти текущие координаты не станут равны координатам перемещения, заданным в начале перемещения как точку на карте, ...в этот момент в алгоритме перемещения условия на смещения по осям становятся ложными, и начислений смещения больше не будет, ...следствие - моб стоит в заданной точке.
Далее, "алгоритм действия" фиксирует близость цели и запускает процедуру выполнения атаки.
Все просто. У вас будет порядок алгоритмов такой:

1) Алгоритм перемещения;
2) Алгоритм поиска цели;
3) Алгоритм действия;
...и так далее, с гибелью и пр. пр. пр. Все работает в цикле по списку объектов и с учетом типов объектов, ...куча условий, фильтрующих объекты.

Grenade 03.03.2010 21:51

Вообще спасибо Вам огромное за такую тему!

korand 07.03.2010 01:13

очень полезная тема, правда длинная...

Beermonza 08.03.2010 00:21

Обучение еще длиннее, это всего лишь маленькие уроки, советы.

Alexan-Dwer 14.03.2010 23:10

Да, тема довольно интересная, правда, местами сложная для понимания.
Но, у меня возникло небольшое разногласие: простите, если я ошибаюсь, но мне кажется что Банк текстур не нужная трата ресурсов. Что бы избавиться от непониманий в дальнейшем, привожу код своего Банка:

Код:

// В глобальных переменных задаю массивы карты и банка
Map: array[0..19,0..19] of word; Bank: array[1..256] of TBitmap;
// Процедура создания банка
procedure TForm1.CBank;
var
i: word;
begin
for i:=1 to 256 do
begin
Bank[i]:= TBitmap.Create; Bank[i].LoadFromFile('текстуры\'+IntToStr(i)+'.gif');
end;
end;
{Теперь, когда банк создан, и массив map заполнен, я рисую карту:}
procedure TForm1.DMap;
var
a,b: word;
begin
for y:=0 to 19 do for x:=0 to 19 do
begin
Form1.Canvas.Draw(10*a,10*b,Bank[Map[a,b]]);
end;
{Вот тут можно почистить Банк дополнительным циклом с методом FreeImage}
end;

В итоге получается: 256 битмапов с текстурами в памяти (если их не почистить, но даже с чистыми картинками массив все же “висит” в памяти).
Скажите, неужели толк от Банка текстур настолько выше и значительней, чем простое создание 1-го битмапа, загрузки в него текстур и очистки этого битмапа, после окончания работы с ним???

P.S. Тему читал всю, но заметил лишь два пункта превосходства Банка текстур, хотелось бы больше. :rolleyes: :(

Гром 14.03.2010 23:48

Зачем же обязательно 256, когда можно использовать ровно столько, сколько надо? Используйте динамический массив строго необходимого размера, и будет вам оптимальное использование ресурсов. (Хотя уже в упор не помню, есть ли в Паскале динамические массивы, но в Delphi точно должно быть что-то подходящее!)
Можно, конечно, хранить все текстуры в виде одного сложного битмапа - это вопрос удобства, но все равно где-то должна храниться разнообразная информация о картинке (размеры, количество кадров в анимации, прозрачность и т.д. и т.п.)
Или вы имеете в виду каждый раз грузить из файла одну текстуру, рисовать ее, выгружать из памяти, грузить следующую, рисовать, выгружать, и так далее множество раз в секунду? Вот тогда это уж настоящая пустая трата ресурсов!;)

Alexan-Dwer 15.03.2010 00:42

Уважаемый Гром, я не профессионал и все что пишу, основано на моих собственных умозаключениях и на том, что видел своими глазами. Вот вы в своем сообщение говорите, что происходит при использовании буфера:
Цитата:

...грузить из файла одну текстуру, рисовать ее, выгружать из памяти, грузить следующую, рисовать, выгружать, и так далее множество раз в секунду...
А что мы имеем при Банке текстур? Загрузка и рисование присутствует, разве что вот выгрузки нет; но зато у нас есть целый массив с картинками, которые весят как минимум по 3 Кб, а если карта как в примере 20x20? Тогда получим 1Мб на одни картинки, а то и больше. Я понимаю, что когда речь идет об одинаковых текстурах, Банк текстур это очень хороший выход. Но, один раз я имел случай сделать screenshot 2D игры и то, что я там увидел, было жестоко — все текстуры были похожи, но различались примерно на 7 точек из 16 (насколько помню). А вот на первый взгляд казалось, что они просто копия друг друга. Для подтверждения увиденного открыл папку текстуры, скопировал около 40% и сравнивал в программе Photoshop с максимальным увеличением. Вот сейчас, когда вернулся к этому вопросу, думаю, есть ли смысл делать Банк текстур.

Цитата:

Зачем же обязательно 256, когда можно использовать ровно столько, сколько надо?
Это для примера :) К тому же, чем больше текстур, тем, на мой взгляд, меньше необходимость использовать Банк. Я считаю, что когда текстур мало, банк очень актуален, а вот когда есть всякие “каемки” и прочий реалистичный блеск, который увеличивает кол-во текстур, то тут уж очень спорный вопрос…

Гром 15.03.2010 01:14

Не отличающиеся внешне текстуры - это просто грубая ошибка художника/дизайнера. Тому, кто их делал - руки оторвать и пришить в более правильное место.
Так что, исходя из того, что разные текстуры выглядят достаточно отлично друг от друга, получаем, что либо текстур гораздо меньше, либо толк от них всех все равно есть.
Потом, при работе с банком текстур есть однократная загрузка с диска, а потом идет работа с оперативной памятью, что гораздо быстрее! А каждый раз читать с диска одну маленькую картинку, потом читать с диска еще 399 маленьких картинок, и так, скажем, 25 раз в секунду... Очень снижается быстродействие.
С банком текстур мы не имеем такой проблемы, расплачиваясь за существенное быстродействие сравнительно небольшим расходом оперативки, а если текстуры часто повторяются - то и совсем небольшим.

В общем, при увеличении числа текстур в варианте с банком - объем использования оперативной памяти растет линейно, в варианте без него - линейно же падает быстродействие. Вот только коэффициенты пропорциональности не в пользу варианта без банка.

Beermonza 15.03.2010 01:58

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

Попробую более доступным языком выразить все, что было уже сказано и показано в примерах.
Вот у нас некий шаблон карты. Он закодирован, и на каждую текстуру клетки карты приходится свой код. В структуре есть матрица индексов текстур (это слой карты), есть динамический массив банка текстур, например Array of TGBank. Идет загрузка данных, при этом натыкаясь на первый байт кода текстуры банку задается размер 1, в ячейку помещается текстура и все сопутствующие данные по типу (размеры, смещения и пр.) в матрицу слоя записывается по координатам (x,y) индекс ячейки банка. Далее, переход на следующий код клетки, ...массив банка проверяется на наличие уже загруженной такой текстуры от 1 до размера массива, если такой нет, то идет увеличение размера массива на 1 и заполнение последней ячейки текстурой и данными к ней, также в матрицу слоя идет индекс ячейки банка. На очередном шаге встречается очередной код карты, при проверке банка оказалось, что такая текстура уже загружена, ...загрузка пропускается, вместо нее в матрицу пойдет индекс найденного совпадения кода на карте и в проверяемой ячейке банка. И так далее, пока не будет считана вся карта.

Банк текстур никогда не очищается, если эта карта, или ее участок является активным в игре. Если нужна другая карта, тогда банк освобождается и заполняется заново, но уже текстурами к новой карте.
Алгоритм построения кадра игры всегда пользуется индексами матрицы карты и берет текстуры непосредственно из банка, ...никакого другого хранения текстур в игре, кроме как в банке, быть не должно.

Что в итоге? ...если текстурщик все продумал и создал набор оптимальных текстур, с помощью которых можно построить поверхность любой нужной сложности, то в памяти никогда не будет количества текстур, равных количеству клеток на карте, ...в том и заключается оптимизация.
Вот у нас слой поверхности: трава, земля, дорога. Если прикинуть, то по 5 вариантов достаточно для неоднообразности. В сочетании со случайным наполнением и точным расположением нужных типов текстур карты 20х20, благодаря банку в памяти будет всего 15 текстур, ...иначе 400 (!) ...а если текстуры 25х25, то в размерах соотносится как 27 Кбайт к 720 Кбайт (!) ...есть разница?
То же самое касается и слоя объектов, где текстуры уже будут поболее (вплоть до 400х500 пкс), понятно, что нет смысла держать в памяти копии текстуры одного и того же типа дерева, здания, части горы, ...да чего еще угодно.

Вот в этом суть банка текстур, при правильном его создании и использовании.

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

Alexan-Dwer 16.03.2010 22:18

Цитата:

Гром говорит умные вещи, стоит поверить на слово, ...если только ... нет желания все же разобраться самому.
Желание есть, поэтому и разбираюсь. Для меня главное то, что я все же правильно мыслил: без Банка объем используемой ОЗУ меньше, но скорость тоже не велика.
Цитата:

Идет загрузка данных, при этом натыкаясь на первый байт кода текстуры банку задается размер 1, в ячейку помещается текстура … в матрицу слоя записывается по координатам (x,y) индекс ячейки банка. Далее, переход на следующий код клетки, ...массив банка проверяется на наличие уже загруженной такой текстуры ..., если такой нет, то идет увеличение размера массива на 1 и заполнение последней ячейки текстурой и данными к ней….
Насколько я понимаю, этот вариант используется в случаях, когда название текстуры состоит из букв (road.bmp, water.bmp) и идут не по порядку (1.bmp, 3.bmp, 8.bmp и т.д.), или же для того, что б уменьшить объем ОЗУ и загружать только необходимые текстуры.
  • В первом случае я бы их просто переименовал по порядку (1.bmp, 2.bmp...) и полностью загружал циклом:
    Код:

    for i:=1 to 255 do
    begin
    Bank[i]:= TBitmap.Create; Bank[i].LoadFromFile('текстуры\'+IntToStr(i)+'.gif');
    end;

  • Второй случай сложнее, поэтому лучше действительно воспользоваться советом от Beermonza.
В заключении хотел бы привести свою систему 2D RPG:
Пока что основные составляющие это: игрок и карта. Теперь сама реализация:

Тип игрока:
Код:

TPlayer = packed record
// Координаты.
X, Y: Byte;
end;

Работа с картой:
Код:

// Банк текстур.
Bank: array[1..256] of TBitmap;
// Вся карта.
FullMap: array[0..190,0..190] of Byte;
// Часть карты, выводимая на экран.
ScreenMap: array[0..19,0..19] of Byte;

В событие FormCreate происходит загрузка текстур, потом карты. В зависимости от координат персонажа происходит заполнение ScreenMap текстурами из Банка.

Управление персонажем: при нажатии на кнопку W вначале происходит проверка на проходимость и не занятость каким-либо НПС клетки выше персонажа. Если эта клетка свободна, то y координата игрока уменьшается на одну единицу, дальше отрисовывается анимация перемещения модели игрока вверх.

Я сейчас все это только начинаю реализовать, и кое-что пока не совсем понятно. Поэтому прошу объяснить с простыми примерами о том, как значения из FullMap перевести в ScreenMap в зависимости от координат игрока.

И прошу, если у меня в коде или в рассуждениях есть ошибки или не рациональные подходы, пожалуйста, напиши об этом.

Beermonza 17.03.2010 00:29

Вот тут ошибка:

Код:

Bank: array[1..256] of TBitmap;
...тип Byte, который используется в массивах FullMap и ScreenMap имеет строгие границы: 0 - 255. Текстура 256 никогда не появится в игре. Вот так правильно:

Код:

Bank: array[0..255] of TBitmap;
Если набор текстур столь незначительный, что его кодом может быть 1 байт, то и нет смысла называть текстуры по именам, ...достаточно составить таблицу, где каждой текстуре присвоен номер от 0 до 255, ...и игра и редактор будут пользоваться этими кодами, а редактор и списком, чтобы было понятно, что за текстура устанавливается на карту.

По идее ScreenMap не нужен в принципе. Достаточно иметь 4 переменные, которые хранят диапазон выборки клеток карты. Две отвечают за сдвиг от начата карты по-X и по-Y, остальные две размер области экрана, т.е. ширину и высоту в клетках (у вас обе по 20).

Я так понимаю речь идет о классическом расположении персонажа в центре экрана?

Alexan-Dwer 17.03.2010 00:46

Цитата:

Вот тут ошибка
Спасибо :)

Цитата:

Я так понимаю речь идет о классическом расположении персонажа в центре экрана?
По сути да, если я правильно понял вашу мысль. Персонаж может появиться в любом месте, потом при движении смещается по центру, а когда карта заканчивается, он оказывается у ее краев.

Цитата:

По идее ScreenMap не нужен в принципе. Достаточно иметь 4 переменные, которые хранят диапазон выборки клеток карты.
А делать эту выборку так — увеличивать соответствующие переменные, отвечающие за сдвиг и по ним рисовать на canvas?

Beermonza 17.03.2010 16:07

Очень просто.
Вот персонаж в начальной клетке K(0,0), если он центрируется на экране, то мы четко знаем сколько клеток карты нужно, чтобы положение персонажа было в центре. Экран 20х20 - уже ошибка, числа должны быть нечетными. Пусть 19х19, тогда диапазон выборки будет от 0 до (19-1)/2. Теперь для координаты X, ближе к коду. Если сдвиг это DispX, а количество клеток в экране ScreenW, то цикл выборки организуется так:

Код:

For X := 0 to ((ScreenW-1) div 2)+DispX do
  Begin
    ...
  end;

Эта выборка справедлива для координаты X персонажа, до значения (ScreenW-1) div 2, после него выборка станет такая:

Код:

For X := DispX to ScreenW+DispX do
  Begin
    ...
  end;

До того как будет производится выборка идут условия, которые определяют два аргумента цикла X1 и X2, поэтому код видоизменяется:

Код:

If DispX <= (ScreenW-1) div 2 then
  Begin
    X1 := 0;
    X2 := ((ScreenW-1) div 2)+DispX;
  end
else
  Begin
    X1 := DispX;
    X2 := ScreenW+DispX;
  end;

For X := X1 to X2 do
  Begin
    ...
  end;

Для Y аналогично. Disp(X и Y) - переменные, управляемые алгоритмом смещения персонажа, в тот момент когда он переходит на очередную клетку значения переменных увеличиваются или уменьшаются на 1, точнее к ним прибавляется скорость смещения 1 или -1 (смотрите в теме примеры, уровень грубого смещения).

По поводу отображения. Оно теперь не привязано к координатам начала 0,0, а будет плавающим:

Код:

Form1.Canvas.Draw((ScreenW-(X2-X1))*TexW, (ScreenH-(Y2-Y1))*TexH, Buf);
TexW и TexH - размеры текстуры клетки карты в пикселах. Данный пример сильно упрощен из более сложного, в котором персонаж дойдя до края карты отрывается от центра и может свободно перемещаться по углам, карта при этом всегда рисуется во весь экран, а не так как например в Героях Магии и Меча 2-3. Возможно есть недочеты, вы исправите их, если примените код.

Манжосов Денис :) 04.05.2010 18:51

Помогите с редактором
 
Вложений: 1
Объясню суть вкратце: есть редактор, на мой взгляд, с не совсем удобным интерфейсом, но лучше придумать не могу. Что меня смущает: если я хочу, чтобы выбранный объект создавался как препятствие, я щёлкаю на галочку "Препятствие". К примеру, добавляю квадрат как препятствие, второй квадрат как не препятствие(снимаю галочку), третий как препятствие и т.д. Хочется придумать для этой операции вариант получше. Далее...Далее нет смысла объяснять, это очень долго. Во вложении exe редактора. Мне важно ваше мнение, как сделать программу удобней.
Небольшая инструкция:
- Чтобы добавить объект, нажмите на + рядом с пустым полем и выберите любое изображение на вашем компьютере
- Чтобы прекратить расстановку объектов по карте, нажмите "Сброс"
- Чтобы выделить объект, нажмите на него. Вы можете перемещать объект по карте, с помощью стрелок. Чтобы сбросить выделение, нажмите на пустую область карты или на "Сброс"
- Чтобы удалить объект, выберите объект и нажмите Delete
- Чтобы ставить объекты как препятствия, щёлкните на галочке "Препятствие"
- Чтобы создать новую зону, нажмите + рядом с надписью "Зона"
- Чтобы удалить текущую зону, нажмите -
- Чтобы перемещаться по зонам, используйте << и >>
Надеюсь, что вы поможете мне. Спасибо
P.S. Просьба не пользоваться меню - оно не до конца сделано и могут возникнуть проблемы.

like_cloud 07.05.2010 16:10

есть вопрос:

вывожу карту из текстового файла с 0 и 1 (для начала) в буфер (в битмап). Затем копирую ее на канву TImage. Размер минимальной клетки карты 10 на 10. размер карты 70 на 70. Все работает нормально. Если выставить значение размера карты больше 70 по любой стороне (хотя бы 71), то вылетает ошибка о каком-то неверном дескрипторе. Пожалуйста подскажите как поступить.

Beermonza 07.05.2010 19:20

like_cloud, смотрите массив карты в Var, он наверное жестко прописан array[1..70, 1..70] of ...

Манжосов Денис :), exe запускать не хочется, может скринчик покажешь?
Сделай условие на зажатую клавишу. Если например "w" не зажата, лепит без препятствия, если зажата, соответственно, будет препятствие.

like_cloud 07.05.2010 21:11

Цитата:

Сообщение от Beermonza (Сообщение 519513)
like_cloud, смотрите массив карты в Var, он наверное жестко прописан array[1..70, 1..70] of ...

пользовался,кстати, вашим пример,данным ранее где-то в этой теме. Но решил тупо не копировать,а попытаться все обдуманно сделать сам,используя пример.

Нет там массив в 1000 элементов. Щас поэксперемнтировал: можно вывести карту суммарным размером клеток не более 141. Т.е. можно 70 и 71 , 69 и 72 и т.д. назависимо от стороны X и Y. Я "слегка" в недоумении

Манжосов Денис :) 07.05.2010 21:11

Ответ
 
Вложений: 1
Спасибо, Beermonza, что откликнулись. Идея с зажатой клавишей неплохая, можно на Ctrl сделать.
А при запуске программы даже никакое окошко не вылетает? У меня запустилось всё нормально из вложения.
Скриншот редактора прилагается
like_cloud, выложите на форум проект, так будет легче разобраться в проблеме.

like_cloud 07.05.2010 21:48

Вложений: 1
вот держите. Там все пока что сумбурно, только начинаю разбираться с этими делами. Вывод "карты" на форму по нажатию кнопки.
Заодно вопрос: когда-нибудь карта станет большой и будет кушать много ресурсов. На канву чего быстрее всего вывести ее?

Манжосов Денис :) 07.05.2010 22:01

Вложений: 1
Вот что могу сказать: для каждой клетки создаётся свой Bitmap, что очень не желательно, потому как может быть 1000 одинаковых клеток и каждой свой Bitmap, хотя картинка одна и та же. Я ещё удивился, почему так долго загружается =). Также почему нет Assign(Input, lvl); и Close(Input);? Присутствует только Reset(Input);
Код:

j*razfieldX-razfieldX, i*razfieldY-razfieldY
Не совсем понятен код: razfieldX-razfieldX, так как разность равна 0 и смысл умножать на 0? =)
Написал простой пример загрузки карты и вывода изображения карты на экран.

Beermonza 08.05.2010 19:05

Цитата:

Сообщение от like_cloud (Сообщение 519619)
вот держите. Там все пока что сумбурно, только начинаю разбираться с этими делами. Вывод "карты" на форму по нажатию кнопки.
Заодно вопрос: когда-нибудь карта станет большой и будет кушать много ресурсов. На канву чего быстрее всего вывести ее?

Вот тут "корень зла":

Код:

  MapX := 70;
  MapY := 70;
  razfieldX := 10;
  razfieldY := 10;
  BackBuf := TBitmap.Create;
  BackBuf.Height := (mapy)*razfieldX;
  BackBuf.Width := (mapx)*razfieldY;

Вы создаете огромный битмап, но предел для такого типа существует, в него и упираетесь. Несколько раз описывал как с этим бороться. Логикой, ...только так. Если подумать, то на экране вся карта не видна, это факт, ...так зачем ее рисовать всю и держать в памяти? Берем размер экрана и делим его на клетки карты, получается что-то в районе 100х70 для нормального всеми принятого окна 1024х768, берем немного меньше, ибо еще рамки окна и меню "пуск" должно быть видно.
Значит буфер нужен 1000х700, такой должен работать по-любому, что там у вас происходит я не в курсе, если такой не тянет.
Теперь, мы работаем "в цифре", загружаем карту любого размера в массив карты любого размера (предела). Когда нужно отрисовать экран, мы берем диапазон из массива и готовим подложку в буфер. Т.е. нужно начало выборки и размер на экран, делаем цикл и рисуем кусочки в буфер.

like_cloud 08.05.2010 21:46

Цитата:

Сообщение от Beermonza (Сообщение 520103)
Вот тут "корень зла":


Вы создаете огромный битмап, но предел для такого типа существует, в него и упираетесь. <....>

дале-то в том,что минимальная клетка карты 10 пикселей. размер карты можем сделать 70 на 71 (или наоборот) клеток. Получается 700 на 710 пикселей. Где-то четверть экрана,никак не весь(

Beermonza 08.05.2010 23:06

Цитата:

Сообщение от like_cloud (Сообщение 520196)
дале-то в том,что минимальная клетка карты 10 пикселей. размер карты можем сделать 70 на 71 (или наоборот) клеток. Получается 700 на 710 пикселей. Где-то четверть экрана,никак не весь(

Очень странно, ...может у вас ошибка в файле карты? ...натыкается на 4970-й символ и не может загрузить картинку, такой просто нет. Кстати, переход на следующую строку - тоже байт, он будет считан командой Read.

like_cloud 11.05.2010 14:56

Цитата:

Сообщение от Beermonza (Сообщение 520225)
Очень странно, ...может у вас ошибка в файле карты? ...натыкается на 4970-й символ и не может загрузить картинку, такой просто нет. Кстати, переход на следующую строку - тоже байт, он будет считан командой Read.

карта состоит из текста типа "0 1 0 0 0 0 0 1[переход на след. строку]". Получается,если где-то стоит еще пробел вконце строки,То это может быть ошибкой?
..........
проверил карту, был лишний пробел в конце строки. Убрал,все равно ошибка. Сделал новую карту,проверил ее - все равно ошибка. И именно на если карта больше 70 на 71 клетки..

Beermonza 11.05.2010 17:44

В ваших исходниках загружается файл lvl02.txt, в нем физически нет клеток по-X больше 70. В lvl01.txt вроде 200, может в этом ошибка?

...и пробелы ставить не обязательно, пусть подряд идут байты клеток.

CbITHO 26.05.2010 16:29

непонел почему пост исчез((повторю вопрос. у меня игра в которой кот бегает за мышью по форме, но мне нужно сделать на форме лабиринт, и чтоб они бегали по нему. как это осуществить?

Beermonza 26.05.2010 17:16

CbITHO, читайте тему с начала, разбирайте примеры, ...прежде чем задавать вопрос воспользуйтесь поиском по форуму.
Ваш вопрос удален по причине - "глупый" ...можете обижаться, но в нем сокрыта сама сущность понимания вами процессов игростроения. Читайте тему и все вопросы отпадут.

CbITHO 26.05.2010 17:52

я начинал читать ина первых 4 страницах нужной информации не нашол. я б дочитал доконца да мне вот завтро надобы сдать. подскажите хотябы где примерно искать

Beermonza 26.05.2010 18:02

В раздел "помощь студентам", найдете человека, сделает.
А тема начинается по существу после 5-6-й страницы.

M0rf 27.05.2010 01:58

Игра файтинг. Основы уже написал, теперь пытаюсь все упростить. У меня такаой вопрос. В игре используется 5 таймеров: 2 на каждого игрока - 1 на нанесение ударов, 2-й - на получение, +1 таймер на отлов клавиш. Можно ли как-нибудь это упростить?

З.Ы. Игра на C++ Builder 6.0

Гром 27.05.2010 11:09

M0rf, нужно! Использовать ровно один таймер!
Вкратце: отлов клавиш осуществляете в событиях OnKeyDown, OnKeyUp - при этом вы просто запоминаете в соответствующих флагах нажата ли каждая нужная клавиша. При срабатывании таймера смотрите по флагам, какие клавиши нажаты и делаете то, что нужно - у обоих игроков. Нанесение и получение ударов происходит одновременно. Если у вас еще есть какая-то анимация их, т.е. не мгновенное нанесение ударов, то просто в каждый момент нанесение удара будет на какой-то стадии. Если вдруг противник оказался в радиусе действия удара - тут-то ему и больно стало!
Кстати, я уже однажды распинался насчет файтинга и таймеров вот в этой теме.

M0rf 29.05.2010 01:34

Почитал. Попытался впихнуть все в один таймер. KeyDown и KeyUp у меня используются так как ты написал (пасиб кстати), а вот с таймером некоторые проблемки:
1) Таймер обрабатывает только одну функцию. Пусть и быстро (при выполнении действий с небольшим количеством кадров это незаметно), но при использовании действий с большим количеством кадров это ощутимо.
2) Выполняется только одна анимация в условии, даже если она не одна (нанесение удара и его получение обрабатываются в одном условии. В итоге я наношу удар одним персонажем с воспроизведением анимации удара, а второй персонаж получает урон, но анимации нет)

Гром 29.05.2010 10:27

Цитата:

Таймер обрабатывает только одну функцию.
То есть?
Пихаете в функцию-обработчик события OnTimer вызовы всех функций, каких нужно и делается все хорошо.
Код:

при использовании действий с большим количеством кадров это ощутимо.
Что именно ощутимо? Мерцать начинает? Это тогда двойная буферизация нужна.
Цитата:

нанесение удара и его получение обрабатываются в одном условии
Делайте что-то вроде этого - при нанесении удара начинается воспроизведение соответствующей анимации (например, где-то флажок такой помечаете, что игрок сейчас наносит удар, и храните, так сказать, на сколько процентов удар завершен), на получение удара - то же самое (и, скажем, если игрок "в процессе получения удара", то на нажатие клавиш или только на клавиш с ударами он не реагирует - если захотите так сделать). Потом, далее по списку пунктов, обрабатываемых в таймере - смотрите, не находится ли данный игрок в процессе нанесения удара и в процессе получения удара. Если это так - рисуете соответствующий кадр анимации.
Вот такую схему могу вам предложить.

M0rf 30.05.2010 02:22

По первому: таймер срабатывает раз в 40 млсек. и выполняет действие, которое удовлетворяет условию. Так вот, если действие состоит из 4-5 кадров - они выполняются довольно быстро, и когда таймер будет обрабатывать другое действие, нам кажется, что они происходят одновременно. А если действие, скажем в 30-40 кадров. Все остальные действия приостанавливаются и возобновляются после его окончания.
По второму: неплохая идея. Попробую обязательно.

Beermonza 30.05.2010 19:35

M0rf, внимательно читайте тему, ...несколько раз упоминался собственный тип массива юнитов. У юнита есть запись, отвечающая за состояние, т.е. тип анимации, которую он выполняет, ...есть запись, отвечающая за номер текущего кадра. Существует цикл по числу юнитов в игре, внутри цикла Case на состояние (тип анимации), в каждом пункте которого прописаны все состояния, и в каждом количество кадров, ...условия на конец анимации и переход на другое состояние.
В любой момент времени будут обрабатываться все юниты по одному и тому же таймеру, но каждый будет выполнять свои действия и анимацию, исходя из своих записей. Вот упрощенная модель:

Код:

  // цикл по числу юнитов
  For i := 1 to nUnits do
    Begin
      // если юнит в игре
      If Units[i].InGame then
        Begin
          // работаем с записями юнита
          With Units[i] do
            Begin
              Case UAction of
              //0 - флаг нормального состояния
              0: Begin
                    UAnimType := 0;  // тип анимации
                  end;
              //1 - флаг действия 1
              1: Begin
                    UAnimType := 1;  // тип анимации
                    // на последнем кадре сцены действия
                    If UFrame = {номер последнего кадра} then
                    Begin
                      UAction := 0; // переход на нормальное состояние
                    end;
                  end;
              //2 - флаг действия 2
              2: Begin
                    // ----
                  end;

              // сколько еще нужно типов действия

              end; // case


              // Смена кадра анимации
              UFrame := Inc(UFrame);
              // проверка на переполнение
              If UFrame > {количество кадров анимации от типа} then UFrame := 0;

            end;
        end;
    end;

В этой структуре могут быть записаны и процедуры. Когда идет последний кадр некоторого типа анимации, в условии идет не только смена состояния, но и выполняется некая процедура, например, удар достиг конца, на последнем кадре запускается процедура расчета урона, ...или есть промежуточное условие на некоторый кадр, оно запускает процедуру расчета урона, а анимация продолжается до последнего.

M0rf 02.06.2010 03:16

Ура! Теперь у меня один таймер. Все неплохо работает, анимации корректно воспризводятся, но сложно регулировать скорость воспроизведения. при некоторых ударах получается, что анимация получения удара выполняется быстрее, чем нанесение. Пытался вручную менять интервалы у таймера, но это влияет на все скорости воспроизведения анимаций, что не решает проблемму. Возможно нужно использовать sleep() ?

З. Ы. Не подскажите ли мне аналог команды With на С++. Как я понял в данном примере, эта команда позволяет не писать каждый раз Units[i] при обращении к элементам. В helpe по С++ ее нет.

Гром 02.06.2010 08:57

Цитата:

при некоторых ударах получается, что анимация получения удара выполняется быстрее, чем нанесение
Похоже, дело тут у вас в количестве кадров каждой анимации и другого адекватного совета, кроме как унифицировать количество кадров (или хотя бы подогнать для этой ситуации) тут быть не может.
Цитата:

Не подскажите ли мне аналог команды With на С++.
Эк вы вовремя!:d Просто как раз в данный момент в разделе по C++ висит на этот счет тема.
Говоря кратко - нет такого аналога в C++, только в функциях-членах вы не пишете, к какому объекту обращаетесь.

И еще добавлю, что при написании игры (и вообще любой нетривиальной программы) на C++ часто стоит активно использовать ООП. Если Pascal и Delphi несмотря на поддержку этой парадигмы часто оказываются склонны к функциональному программированию, что выражается хотя бы в разнице между записями и классами (отсутствие функций-членов и наследования в записях), то C++ является в противовес Си ориентированным именно на ООП и принципиальной разницы между структурами и классами там нет вообще никакой. Поэтому я советую использовать те средства, которые ближе выбранному вами языку (C++ в данном случае) - в частности, активно использовать функции-члены, например, таким образом:
Код:

for (int i = 0; i < nUnits; i++)
//Или вы можете использовать не массив, а один из стандартных контейнеров с его итераторами
 {
 if (Units[i].inGame())
  Units[i].Draw();
 }

class Unit
 {
 public:
 //...
 void Draw();
 //...
 private:
 int UAction; //Или это enum
 //...
 };
void Unit::Draw()
 {
 switch(UAction)
  {
  case 0: {/*анимация первого типа*/}; break;
  case 1: {/*анимация второго типа*/}; break;
  }
 }

Это, конечно, очень грубая схема и скорее только иллюстрация на тему того, в каком направлении вам стоит думать, работая конкретно с C++.

Вадим Буренков 02.06.2010 12:52

Цитата:

анимации корректно воспризводятся, но сложно регулировать скорость воспроизведения. при некоторых ударах получается, что анимация получения удара выполняется быстрее, чем нанесение. Пытался вручную менять интервалы у таймера, но это влияет на все скорости воспроизведения анимаций, что не решает проблемму. Возможно нужно использовать sleep() ?
sleep, как и изменение скорости основного таймера не поможет, так как повлияет на скорость всей игры. В своих анимациях я делал задержки через переменную-счетчик. Вот тут можешь почитать про теорию т.к. вопрос уже обсуждался:
http://www.programmersforum.ru/showthread.php?t=70140
Почитай там мои посты, посмотри мою демку (правда она на Delphi, но как я понял ты его понимаешь). Смысл в том, что есть переменная, она каждый цикл таймера возрастает на 1. Как она становится равной, например 10 происходит ее сброс на 1 и выполняется код анимации. В итоге анимация работает в 10 раз медленнее таймера. Ту же систему можно использовать при других задержках чтобы не захламлять игру лишними таймерами.

Beermonza 02.06.2010 16:30

Цитата:

Сообщение от Вадим Буренков (Сообщение 542869)
... Смысл в том, что есть переменная, она каждый цикл таймера возрастает на 1. Как она становится равной, например 10 происходит ее сброс на 1 и выполняется код анимации. В итоге анимация работает в 10 раз медленнее таймера. Ту же систему можно использовать при других задержках чтобы не захламлять игру лишними таймерами.

Да, использую такой же алгоритм задержки (в играх типа РПГ очень чато приходится рулить анимацией, то же заклинание "медлительности", персонаж медленно перебирает ногами и перемещается тоже медленно), вот пример:
Код:

If FrameWait = 0 then Inc(Frame); // смена кадра
Inc(FrameWait); // счетчик задержки
If FrameWait = AnimWait then FrameWait := 0; // задержка равна установленной


M0rf 03.06.2010 01:46

Цитата:

И еще добавлю, что при написании игры (и вообще любой нетривиальной программы) на C++ часто стоит активно использовать ООП.
Согласен на сто процентов. Но поскольку я новичек в создании игр, то совершил все возможные ошибки. Так в проге у меня 4 Image (1 фон, 2 бойца, полоса жизней). Знаю, что лучше переделать хотя бы под Canvas (в идеале OpenGL). Игру начинаю переделывать под ООП только сечас, поэтому и спроил об аналоге команды (писать полное обращение - захломляется код). В идеале планирую перенести в класс не только переменные бойцов, но и выполняемые функции. Но это уже позже.
Цитата:

Смысл в том, что есть переменная, она каждый цикл таймера возрастает на 1. Как она становится равной, например 10 происходит ее сброс на 1 и выполняется код анимации. В итоге анимация работает в 10 раз медленнее таймера. Ту же систему можно использовать при других задержках чтобы не захламлять игру лишними таймерами.
отличный способ. Сам думал над введением новой переменной, отвечающей за скорость, но не знал как реализовать. Попробую отпишусь.

M0rf 13.06.2010 01:42

Сессия закончилась, можно иделом заняться.
Решил переделать вывод графики через Canvas в один Image. нашел пару примеров (в С++ синтаксис не такой как в Delphi), но возникли трудности:
TPicture *fon=new TPicture; - задаю указатель на фон игры
fon->Bitmap->Width=1280;
fon->Bitmap->Height=800; - указываю ширину и высоту
fon->Bitmap->LoadFromFile("Арена1.bmp"); - загружаю
Image1->Canvas->Draw(0,0,fon->Bitmap); - рисую.
Выскакивает ошибка при запуске программы: "Stream read error". Все сделано в соответсвии с примером. Есть ли ошибка в коде, и как правильно сделать вывод?

И еще, про классы. В начале планировалось использовать один класс - Fighter, который будет хранить все переменные, функции ударов, движения, получение урона. В общем все функции. Но один товарищ посоветовал мне писать несколько классов: описание бойца, описание анимаций и др. Никак не могу понять преимуществ такого способа. Как, на ваш взгляд, лучше писать классы?

Гром 13.06.2010 07:58

Не надо рисовать все в один Image. Рисуйте сразу на форму. В реализации разницы никакой - т.к. вывод происходит через канву, которая у Form и Image одна и та же, а результат уже ближе к идеалу.
Также вместо TPicture советую TBitmap (уже хотя бы потому, что TBitmap является членом TPicture и это именно через него вы работаете).
Ошибка, возможно, из-за использования русских букв (вообще у Билдера с русскими символами и взаимодействием их с внешним миром все очень плохо).
Цитата:

И еще, про классы. В начале планировалось использовать один класс - Fighter, который будет хранить все переменные, функции ударов, движения, получение урона. В общем все функции. Но один товарищ посоветовал мне писать несколько классов: описание бойца, описание анимаций и др. Никак не могу понять преимуществ такого способа. Как, на ваш взгляд, лучше писать классы?
Один-единственный класс (особенно если с единственным экземпляром) - это еще не ООП. Это всего лишь чуть лучше, чем оставить все функции и данные вообще без обертки (в лучшем случае - в пространстве имен). Без множества классов в ООП не обойтись просто по той причине, что Объектно-Ориентированное Программирование предполагает множество классов, а не один (классы, их взаимодействие, наследование, и т.п.) Если у вас есть какая-то сущность - скорее всего, ее стоит сделать классом. Хотя меру тоже надо знать и подходить к процессу с точки зрения логики.
Вообще - почитайте Страуструпа, он много про ООП писал.

M0rf 18.06.2010 10:59

Блин, столько времени и все зря. Уже по-всякому перепробывал. Или я что-то недопонял или чего-то не хватает Builder'у. Смотрим сами:
Graphics::TBitmap *tmpBitmap = new Graphics::TBitmap(); //создаем битмап
tmpBitmap->LoadFromFile("1.bmp");// загружаем изоьражение (специально переименовал, чтобы русских букв не было)
Form1->Canvas->Draw(0,0,tmpBitmap);//отображаем рисунок на форме, начиная с координаты (0,0)

По идее, все должно отображаться. Но при запуске вылетает ошибка Stram read error. При загрузке этой же картинки в Image (Image1->Picture->LoadFromFile("1.bmp")) все грузится нормально. Может быть кто-нибудь выложит пример (самый простой), чтобы я мог проверить - будет ли он у меня работать или нет?

Beermonza 18.06.2010 20:56

С проблемами в коде в свою созданную тему, здесь только фундаментальное, на словах или в коде.

BASSON_XVI 14.07.2010 10:04

Здравствуйте 49 страниц не осилил! :)
У меня карта собирается из текстур 32х32 герой 64х32 ну и деревья и прочие здания разных размеров. Мне интересно как правильно отрисовывать героя и за деревьями и перед... Я не могу передвинуть героя на основания дерева (ствол) но под крону что находиться в ячейки выше могу и тут нужно что бы герой был под кроной дерева и на оборот если герой стоит на 1 ячейку ниже основания дерева(ствола) то мне нужно рисовать героя не переднем плане а дерево на заднем. Вопрос в следующем как это правильно делать? Я кончено могу рисовать героя в цикле отрисовки карты и смотреть в какой он ячейки и что вокруг него если он выше дерева то его первым рисовать дерево вторым и на оборот. На сколько это правильно?

apromix 14.07.2010 11:04

Вот, столкнулся с проблемой ИИ в игре РПГ. Подскажите (может у кого и пример кода есть), как сделать врагов более умными, то есть чтобы не видели ГГ сквозь стены, кидались на ГГ, если у них полно здоровья и убегали, если мало и т.п.

Вадим Буренков 14.07.2010 12:55

Цитата:

Я кончено могу рисовать героя в цикле отрисовки карты и смотреть в какой он ячейки и что вокруг него если он выше дерева то его первым рисовать дерево вторым и на оборот. На сколько это правильно?
Делай так. Ну еще у DX/GL для этого можно использовать z-buffer.
Цитата:

как сделать врагов более умными, то есть чтобы не видели ГГ сквозь стены, кидались на ГГ, если у них полно здоровья и убегали, если мало и т.п.
Делай систему AI. Чтобы не видели сквозь стены - есть алгоритмы. Поведение можно например сделать так: у каждого врага есть типы поведения. Например если здоровье>30 то тип поведения атака, а если меньше то бегство. Можно также смотреть сколько здоровья у игрока. Например если 200 а у противника 50 и он слабее то тоже бежать и.т.п. Таких факторов влияющих на поведение AI может быть много, чем больше тем лучше.

__________________

Beermonza 14.07.2010 16:13

BASSON_XVI, если правильно организовано построение скелета карты и распределение в нем объектов, то все работает автоматически.
Дерево растет с корня, поэтому картинка смещается вверх на высоту текстуры минус пол клетки карты. Аналогично смещается персонаж. Как только персонаж находится по-Y выше дерева, хоть на 1 клетку, он будет позади него, ...почему? ...цикл обработает сначала персонажа, у него Y меньше, а следом дерево.
Строения смещаются в зависимости от основания. Если они занимают 1 клетку, то как в случае с деревом, если 3х3 клетки, то в центре будет смещение, все клетки основания здания должны быть непроходимыми, тогда персонаж пройдет вокруг и его появление снаружи и за зданиями будет по всем правилам. Крупные здания нужно разбивать на части, работать как с пристройками.

apromix, в каждом такте обработки моба запускается процедура. В ней куча условий. Самое первое - цикл обзора, т.е. моб сканирует вокруг себя карту на определенный радиус. Условие: если на карте обнаружился объект, проверить количество жизни. Если количество жизни больше чем у моба, то с вероятностью 80% выбрать произвольно точку отступления. Если жизни меньше или равно, то с вероятностью 90% взять координаты цели, отправить в процедуру перемещения, ...моб будет топать до цели. Он все время, каждый такт, будет выполнять все описанное ранее, и будет реагировать на перемещение цели, ...всегда будет идти к ней, как бы она не убегала. Цель может потеряться, если она уйдет каким-то образом за радиус обзора, тогда моб остановится и удалит у себя цель. Последняя проверка на дистанцию атаки. Если дистанция для нападения достаточная, то остановиться и перейти в режим атаки. Если по какой-то случайности или закономерности жизней у моба станет меньше чем у цели, он свалит. Или можно создать очередное условие на проверку режима. Если моб в режиме атаки, то не выполнять некоторые пункты выше, например, проверку на количество жизней, чтобы моб бился до конца. Тут же могут быть условия как пользоваться восстановлением жизни, лечиться или нет, когда и что делать, какими средствами.

BASSON_XVI 19.07.2010 20:13

Не рандомистый рандом!
 
Довольна странная функция random(); она постоянно выбирает одни и те же цифры, то есть от запуска к запуску пробной демки моб ходит одинаково и постоянно уходит куда то вниз выделенного ему квадрата для ходьбы!
Выбор направления 0-3 то есть random(3); И насколько я вижу чаще всего выпадает именно 0. Как с этим бороться? Ниже кусок кода ходьбы мобов:
Код:

      if Mobs[i].CH <= 0 then
      begin
        Mobs[i].CH := random(random(10));
        if random(10) < 6 then Mobs[i].STOP := random(255);
        Mobs[i].N := random(3);
      end;
      if Mobs[i].STOP <= 0  then begin
      case Mobs[i].N of
      0 : Mobs[i].Y:=Mobs[i].Y+SpeedG;
      1 : Mobs[i].X:=Mobs[i].X-SpeedG;
      2 : Mobs[i].X:=Mobs[i].X+SpeedG;
      3 : Mobs[i].Y:=Mobs[i].Y-SpeedG;
      end;
      .......

Ниже в этом же цикле отнимается шаг и рассчитывается в какую ячейку перешел моб...

Гром 19.07.2010 20:40

Не помню точно, как в паскале, но по идее нужно сначала вызывать функцию randomize, чтобы ряды случайных значений каждый раз были разными.

Beermonza 19.07.2010 21:03

Цитата:

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

Все верно. Перед кодом выбора и обработки нужна команда взятия нового ряда Randomize.

Ponkole 19.07.2010 21:27

люди кто нибудь можете пожалуиста создать текстовый фаил, содержащии страницы данной темы ато у меня инет тормознутый (оооооооооочень) за 3 день только 10 страниц прочитал (сидел где - то по часу в день)

DomiNick 19.07.2010 21:36

Хм... Сейчас сделаю... :) Чуть позже в это же сообщение добавлю... :)

BASSON_XVI 19.07.2010 21:46

То есть перед каждым random(); вызывать randomize; ???

Ponkole 19.07.2010 21:52

BASSON_XVI вызывать randomize надо в начале главных циклов например вначале процедур типа:


Procedure blabla(bla);
begin
randomize;
blablabl:=random(10);
blablaba:=random(10);
blablala:=random(10);
end;




Hosted by uCoz