Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  13:13[Войти] | [Зарегистрироваться]
Ответ на вопрос № 83659

15-05-2019 13:59
Всем привет. Подскажите пожалуйста. Кто ни будь делал игру на подобии BrickShooter?
Как вообще там все строится? Мне кажется я не правильно отрисовал игровое поле. Так как если один тайл уже в движении, то щелкнув по другому - первый останавливается. И если первоначальные координаты тайла изменилились, а на его место передвинулся очередной тайл. Как запустить очередной тайл?
У меня в рекорд записываются координаты X,Y(нужно или нет?), Check- если тайл не дошел до финиша- для того что бы когда исчезнет преграда он продолжил движение, Enabled -если тайл удален, ну и pic- номер рисунка.

type
  TTile = record
      X, Y: integer;
      Check, Enabled: Boolean;
      pic : byte;
end;

var
Tile : array [0..20,0..20] of TTile;
M : TPoint;
TX, TY, selx, sely, openx, openy : integer;

///////////////
procedure TMainForm.ShapeMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
    if (Button = mbLeft) then begin
      openx := selx;
      openy := sely;

procedure TMainForm.ProcessEvent(Sender: TObject);
begin
    GetCursorPos(M);
      TX := M.x - MainForm.left-3;
      TY := M.y - MainForm.top-26;

      selx := (TX-15) div 30-5; //    X:= x-1;
      sely := (TY-26) div 30;

  with Tile[openX,openY] do begin
          if (X>=230)then
          X:= X-5;
        end;
        with Tile[openX+1,openY] do begin
          if X>=710  then
              X:= X-5;
        end;
        with Tile[openX+2,openY] do begin
          if X>=740  then
              X:= X-5;
        end;

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

07-06-2019 22:55
>>> Не соображу как удалить те которые вышли за предел или как сделать что бы самоуничтожились.
Свои координаты кубик меняет в Process**** (либо Motion, либо Event), так что именно там (если вы брали за основу мой код) надо выставить влажок Dead:=true. "Сборщик мусора" удалит такие кубики.
>>> не могу кликнуть по кубику который перешел на другую сторону. Нужно как то перерисовать все поле? Или переписать Bricks с изменившимися кубиками?
Не совсем понял, что значит "перешёл на другую сторону"? Это значит, что кубик, выдвинувшийся справа, должен "телепортироваться" налево? Не вижу проблемы. При такой "телепортации" вы в любом случае пересчитываете координаты, так что клик в любом случае будет проходить. Полагаю, у вас ошибка в пересчёте координат в ProcessMotion, которая просчитывает эту "телепортацию". Или вы что-то другое имеете в виду?

05-06-2019 05:41
то Python, спасибо за наставления. Изменил и добавил функции. Кубики бегают по полю.
1)Не соображу как удалить те которые вышли за предел или как сделать что бы самоуничтожились.
2)не могу кликнуть по кубику который перешел на другую сторону. Нужно как то перерисовать все поле? Или переписать Bricks с изменившимися кубиками?
У меня на движке Asphyre, но для примера переписал Ваш код, стал чуть длиннее, но так понятней что и как. Могу выложить если нужно.

02-06-2019 01:15
Ах да, если у вас стен не будет в принципе, то можно обойтись и без обратного хода волны. Просто при попытке (чем она вызвана, кстати?) передвижения кубика он будет отправлять сообщение соседу справа "Сдвигайся" и всё. Нужно будет, правда, ещё добавить код, который проверяет, что кубик вышел за пределы игрового поля (согласно моей идеологии, это должно проверяться в GameSystem, но в принипе, можно и чтобы кубик сам ликвидировался при пересечении поля), чтобы не засорять умершими кубиками линейный список.

02-06-2019 01:10
>>> Подскажите, если использовать Ваш код, то для поиска (соседей) нужно будет добавлять и (function FindNeighbourRight(Brick:TBrick):TBrick;)
Да, именно так (если потребуется работа с соседями справа и слева). Возможно, имеет смысл сделать одну процедуру вида FindNeighbour(NeighbourType:(ntLeft,ntTop,ntRight,ntBottom)):TBrick; псевдокод, не пытайтесь скомпилировать, чтобы избежать дублирования кода при проверке координаты X на ntTop, ntBottom, но это необязательно.
>>> когда кубик пройдет все игровое поле и столкнувшись с параллельным кубиком, он его сдвинул, а не остановился перед ним
Для этого у меня в сообщении есть поля _source и _target. Обратите внимание, _source в моём коде нафиг не нужен, может показаться, что он лишний. Но это не так - в вашем случае он пригодится. Назовём это "обратным ходом волны". Принцип будет следующий: кубик А отправляет своему соседу справа Б сообщение и, если Б может двигаться (не упёрся в стену, например, если у вас стены будут), то Б сдвигается на свободное место и отправляет обратно А сообщение: "Сдвигайся, свободно!". Соответственно, если А пытался сдвинуться как запрос от кубика Г, то он отправит обратно Г аналогичное сообщение "Сдвигайся, свободно!" и так пока не закончится обратный ход волны.
Также на обратном ходе, возможно, имеет смысл проверить, не появились ли пустые места, которые надо заполнить. И если да, то "родить" новых кубиков.
PS: Кстати, предложенный вариант неоптимальный. Каждый поиск бегает по всему линейному списку и это плохо. Было бы лучше сделать некий "кеш соседей" для каждого кубика, потому что скорее всего соседи меняться не будут, а потому, можно будет быть уверенным, что если у кубика Ф был сосед сверху Д, то и через ход, если Д жив, то у Ф по прежнему сосед сверху будет Д. Впрочем, на мелком игровом поле тормоза незаметны.

27-05-2019 01:39
To Python: Подскажите, если использовать Ваш код, то для поиска (соседей) нужно будет добавлять и (function FindNeighbourRight(Brick:TBrick):TBrick;) и  (function FindNeighbourLeft(Brick:TBrick):TBrick;)?
Ну и еще конечно же (function IsNeighbourRight(Brick2:TBrick):boolean;) и
(function IsNeighbourLeft(Brick2:TBrick):boolean;). А как сделать что бы- когда кубик пройдет все игровое поле и столкнувшись с параллельным кубиком, он его сдвинул, а не остановился перед ним?   

23-05-2019 21:24
to Den Sarych .Если вы про пример Python'а Нет я имел в виду тот пример (код в начале вопроса). Там ведь двухмерный массив (Tile : array [0..20,0..20] of TTile;) И клик производится по квадратику (Tile[openX,openY]).

23-05-2019 06:59 | Комментарий к предыдущим ответам
>>>Они передвигаются и создаются, но не получается в двухмерном массиве запустить движение (очередью) и кликнуть по второму когда первый сменил координаты.

Если вы про пример Python'а, то:
- там нет двумерного массива, там есть список квадратиков (одномерный массив Bricks :TList).
- клик производится не по квадратику, а по "игровому полю" (pb :TPaintBox), после чего перебирается целиком весь "список квадратиков", с выяснением, на какой из них пришлись координаты клика (procedure pbMouseDown).
- обработка клика и движение квадратиков - не связаны:
  - раз в 1/4 секунды срабатывает таймер (procedure Timer). В этой процедуре, перебирается весь "список квадратиков" и каждый квадратик смещается на 2 по Y (падает на 2 пикселя за кадр), после чего "игровое поле" перерисовывается.
  - клик игрока происходит где-то между кадров (срабатываниями таймера). При обработке этого клика некоторые квадратики изменяются (Dead := true и удаляются из списка), так что до следующей перерисовки они не доживают.

Или же вы делаете свой вариант?

21-05-2019 07:00
To Ник:
>>> Может быть мне не стоит использовать record
Непринципиально. Просто мне было проще использовать уже готовый TObjectList, чтобы он взял на себя управление временем жизни клеток (TBrick в терминах моей программы).
>>> но не получается в двухмерном массиве запустить движение
Использованная мною очередь сообщений - это один из вариантов, её можно реализовать и другими способами. В том числе и рекурсией (классический волновой алгоритм - вообще рекурсия).
To Den Sarych:
>>> что бы нечто подобное, самостоятельно написал автор вопроса
Понятное дело, но обычно имеем то, что имеем. И в данном случае, автор сам пишет, что в основном пытаюсь что либо сделать изучая исходники.

21-05-2019 01:38
Den Sarych Я еще не дошел до алгоритма поиска соседей. Я всего лишь отрисовал поле и пытаюсь заставить кубики передвигатся как положено (ушел один - на его место передвинулся второй, на место второго третий, а вместо третьего создается очередной). Они передвигаются и создаются, но не получается в двухмерном массиве запустить движение (очередью) и кликнуть по второму когда первый сменил координаты.

21-05-2019 00:11
Python , спасибо, круто получилось. Может быть мне не стоит использовать record?
Den Sarych Я извиняюсь что не очень силен в программировании и в основном пытаюсь что либо сделать изучая исходники, находя в них что то полезное для себя. Понимаю что это не совсем правильно, но на хобби не достаточно времени. Ну как то вот так. И Вам тоже большое спасибо за наставления.

20-05-2019 23:11 | Комментарий к предыдущим ответам
>>>Я тут набросал примерчик...
  Пример симпатичный, отлично иллюстрирует эхотаг.
 
  Но, было желание, что бы нечто подобное, самостоятельно написал автор вопроса. Поэтому я предлагал "проектирование сверху", не от "кадров" и "алгоритма поиска соседей", а от общей компоновки программы, от "задумки логики самой игры".
  Нисколько не лучше вашего примера, но возможно нагляднее для автора вопроса, было бы создание именно клеточных игр (со стационарными клетками). В них обычно создаются массивы целых чисел по размеру поля и алгоритм "логики игры" переводит один массив в другой (пример, те же "крестики-нолики", "жизнь", и т.д.).
  В вашей программе, состояние одно, это одномерный массив Bricks объектов (текущее сотояние квадратиков Bricks[].Point, Color, Dead + "скорость падения" квадратиков dy=2 pix/frame). "Новое" состояние выстраивается  в "старом", изменяя предыдущие значения, ровно в промежутке между кадрами. Здесь (исходя из правил именно этой игры) достаточно одного состояния.
  Ваш пример отражает классический подход, основанный на конвейере обработки кадров. 
  Я же предлагаю идти "от задумки игры". Практически любая компьютерная "клеточная игра" была создана на основе обычной "картонной". А в "картонном" варианте игры, есть только сюжет и "логика игры". Здесь нельзя отталкиваться от "алгоритма поиска соседей квадратика" или от "красивой анимации столкновений".
  Вот этот то "уровень логики игры", отражающий сюжет и правила игры, я и предлагаю разрабатывать (и если можно обособить) в первую очередь. Особенно в целях начального обучения. Чем такой подход, на практике, отличается от классического? Да практически, программный код неотличим. Но, в первом случае вы мыслите категориями сюжета игры, а уже потом перекладываете её на конвейер обработки кадров (уровень механики изображения). Во втором - наоборот.

19-05-2019 13:25 | Комментарий к предыдущим ответам
>>> Не "клетки могут принимать сообщения", а уровень "взаимодействия с игроком"
В любом случае, принимать сообщения будет приложение, которое должно переводить эти сообщения в понятный... назовём так... "игровой подсистеме" вид. Я тут набросал примерчик, без оптимизации, реализация неполная, но как-то работает:

unit Unit1;

interface

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

const
  BRICK_WIDTH=30;
  BRICK_HEIGHT=30;
  BRICK_COLORS:array[0..3]of TColor=(clRed,clBlue,clYellow,clLime);

type
  TBrickEventType=(etDie,etMove);
  TGameSystem=class;
  TBrick=class;
  TBrickEvent=class
    _type:TBrickEventType;
    _source,_target:TBrick;
    Constructor Create(aSource,aTarget:TBrick;aType:TBrickEventType);
  end;

  TBrick=class
    X,Y:integer;
    Color:TColor;
    Dead:boolean;
    function IsInside(PointX,PointY:integer):boolean;
    function IsNeighbour4(Brick2:TBrick):boolean;
    function IsNeighbour8(Brick2:TBrick):boolean;
    // указанный кубик является соседом снизу
    function IsNeighbourDown(Brick2:TBrick):boolean;
    // указанный кубик является соседом сверху
    function IsNeighbourUp(Brick2:TBrick):boolean;
    procedure ProcessEvent(Event:TBrickEvent;GameSystem:TGameSystem);
  end;

  TGameSystem=class
    Events:TList;
    Bricks:TList;
    BottomLevel:integer;
    Constructor Create;
    procedure Init(MaxX,MaxY:integer);
    procedure ProcessEvents;
    function ProcessMotion:boolean;
    function FindNeighbourUp(Brick:TBrick):TBrick;
    function FindNeighbourDown(Brick:TBrick):TBrick;
    function BrickHit(X,Y:integer):boolean;
    Destructor Destroy;override;
  end;

  TForm1 = class(TForm)
    pb: TPaintBox;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure pbPaint(Sender: TObject);
    procedure pbMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  private
    EventSystem:TGameSystem;
    procedure Timer(var M:TWMTimer);message WM_TIMER;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  EventSystem:=TGameSystem.Create;
  EventSystem.Init(pb.Width div BRICK_WIDTH+1,pb.Height div BRICK_HEIGHT+1);
  SetTimer(Handle,1,250,nil);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  KillTimer(Handle,1);
  EventSystem.Free;
end;

procedure TForm1.Timer(var M: TWMTimer);
begin
  if M.TimerId=1 then begin
    if EventSystem.ProcessMotion then
      pb.Invalidate;
  end;
end;

procedure TForm1.pbPaint(Sender: TObject);
var
  I:integer;
  Brick:TBrick;
  Canvas:TCanvas;
begin
  Canvas:=pb.Canvas;
  Canvas.Pen.Color:=clWhite;
  Canvas.Brush.Color:=clWhite;
  Canvas.Rectangle(0,0,pb.Width,pb.Height);
  For I:=0 to EventSystem.Bricks.Count-1 do begin
    Brick:=TBrick(EventSystem.Bricks[I]);
    if Brick.Dead then continue;
    Canvas.Brush.Color:=Brick.Color;
    Canvas.Pen.Color:=clBlack;
    Canvas.Rectangle(
      Brick.X-BRICK_WIDTH div 2,Brick.Y-BRICK_HEIGHT div 2,
      Brick.X+BRICK_WIDTH div 2-1,Brick.Y+BRICK_HEIGHT div 2-1
    );
  end;
end;

procedure TForm1.pbMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if EventSystem.BrickHit(X,Y) then
    pb.Invalidate;
end;

{ TBrick }

function TBrick.IsInside(PointX,PointY:integer):boolean;
begin
  Result:=
    (PointX>=X-BRICK_WIDTH  div 2) and (PointX<=X+BRICK_WIDTH  div 2) and
    (PointY>=Y-BRICK_HEIGHT div 2) and (PointY<=Y+BRICK_HEIGHT div 2);
end;

function TBrick.IsNeighbour4(Brick2: TBrick): boolean;
begin
  Result:=(Self<>Brick2) and
    (abs(X-Brick2.X)<=BRICK_WIDTH) and
    (abs(Y-Brick2.Y)<BRICK_HEIGHT);
  if not Result then
    Result:=(Self<>Brick2) and
      (abs(X-Brick2.X)<BRICK_WIDTH) and
      (abs(Y-Brick2.Y)<=BRICK_HEIGHT);
end;

function TBrick.IsNeighbour8(Brick2:TBrick):boolean;
begin
  Result:=(Self<>Brick2) and
    (abs(X-Brick2.X)<=BRICK_WIDTH) and
    (abs(Y-Brick2.Y)<=BRICK_HEIGHT);
end;

function TBrick.IsNeighbourDown(Brick2: TBrick): boolean;
begin
  Result:=(X=Brick2.X) and (Y=Brick2.Y-BRICK_HEIGHT);
end;

function TBrick.IsNeighbourUp(Brick2: TBrick): boolean;
begin
  Result:=(X=Brick2.X) and (Y=Brick2.Y+BRICK_HEIGHT);
end;

procedure TBrick.ProcessEvent(Event: TBrickEvent; GameSystem: TGameSystem);
var
  I:integer;
  Brick:TBrick;
begin
  // мёртвый кубик не идёт играть в ба-а-а-а-скетбол
  if Dead then exit;
  case Event._type of
    etDie:begin
      Dead:=true;
      // пройдёмся по соседям, удаляя одноцветников
      // получая это сообщение, соседи сделают то же самое
      // получится что-то типа волнового алгоритма с развёрнутой рекурсией
      For I:=GameSystem.Bricks.Count-1 downto 0 do begin
        Brick:=TBrick(GameSystem.Bricks[I]);
        if Brick.Dead then continue;
        if (Brick.IsNeighbour4(Self)) and (Brick.Color=Color) then
          GameSystem.Events.Add(TBrickEvent.Create(Self,Brick,etDie));
      end;
    end;
    etMove:begin
      Brick:=GameSystem.FindNeighbourUp(Self);
      Inc(Y,2);
      if Brick<>nil then
        GameSystem.Events.Add(TBrickEvent.Create(Self,Brick,etMove));
    end;
  end;
end;

{ TGameSystem }

function TGameSystem.BrickHit(X, Y: integer):boolean;
var
  I:integer;
  Brick:TBrick;
begin
  For I:=0 to Bricks.Count-1 do begin
    Brick:=TBrick(Bricks[I]);
    if Brick.IsInside(X,Y) then begin
      Events.Add(TBrickEvent.Create(nil,Brick,etDie));
      ProcessEvents;
      Result:=true;
      exit;
    end;
  end;
  Result:=false;
end;

constructor TGameSystem.Create;
begin
  inherited Create;
  Events:=TList.Create;
  Bricks:=TObjectList.Create;
end;

destructor TGameSystem.Destroy;
var
  I:integer;
  Ev:TBrickEvent;
begin
  For I:=0 to Events.Count-1 do begin
    Ev:=TBrickEvent(Events[I]);
    Ev.Free;
  end;
  Events.Free;
  Bricks.Free;
  inherited;
end;

function TGameSystem.FindNeighbourDown(Brick: TBrick): TBrick;
var
  I:integer;
begin
  For I:=0 to Bricks.Count-1 do begin
    Result:=TBrick(Bricks[I]);
    if Brick.IsNeighbourDown(Result) then
      exit;
  end;
  Result:=nil;
end;

function TGameSystem.FindNeighbourUp(Brick: TBrick): TBrick;
var
  I:integer;
begin
  For I:=0 to Bricks.Count-1 do begin
    Result:=TBrick(Bricks[I]);
    if Brick.IsNeighbourUp(Result) then
      exit;
  end;
  Result:=nil;
end;

procedure TGameSystem.Init(MaxX, MaxY: integer);
var
  I,J:integer;
  Brick:TBrick;
begin
  // создаём равномерно разбросанные по сетке ячейки со случайным цветом
  For I:=0 to MaxX-1 do begin
    For J:=0 to MaxY-1 do begin
      Brick:=TBrick.Create;
      Brick.X:=I*BRICK_WIDTH-BRICK_WIDTH div 2;
      Brick.Y:=J*BRICK_HEIGHT-BRICK_HEIGHT div 2;
      Brick.Color:=BRICK_COLORS[Random(Length(BRICK_COLORS))];
      Bricks.Add(Brick);
    end;
  end;
  BottomLevel:=(MaxY-1)*BRICK_HEIGHT-BRICK_HEIGHT div 2;
end;

procedure TGameSystem.ProcessEvents;
var
  Event:TBrickEvent;
  Brick:TBrick;
  I:integer;
begin
  while Events.Count>0 do begin
    Event:=TBrickEvent(Events[0]);
    Events.Delete(0);
    Event._target.ProcessEvent(Event,Self);
    Event.Free;
  end;
  For I:=Bricks.Count-1 downto 0 do begin
    Brick:=TBrick(Bricks[I]);
    if Brick.Dead then
      Bricks.Delete(I);
  end;
end;

function TGameSystem.ProcessMotion:boolean;
var
  Event:TBrickEvent;
  Brick:TBrick;
  I:integer;
begin
  For I:=Bricks.Count-1 downto 0 do begin
    Brick:=TBrick(Bricks[I]);
    // пропускаем кубики на нижней стороне
    if Brick.Y>=BottomLevel then continue;
    if FindNeighbourDown(Brick)=nil then
      Events.Add(TBrickEvent.Create(nil,Brick,etMove));
  end;
  Result:=Events.Count>0;
  while Events.Count>0 do begin
    Event:=TBrickEvent(Events[0]);
    Events.Delete(0);
    Event._target.ProcessEvent(Event,Self);
    Event.Free;
  end;
end;

{ TBrickEvent }

constructor TBrickEvent.Create(aSource, aTarget: TBrick; aType: TBrickEventType);
begin
  inherited Create;
  _source:=aSource;
  _target:=aTarget;
  _type:=aType;
end;

end.


В моём примере игровая подсистема, игровые клетки и собственно приложения обмениваются сообщениями-"событиями". Благодаря этому, можно реализовывать достаточно простым и естественным способом правила игры (например, волновой алгоритм поиска удаляемых клеток и такой же волновой алгоритм поиска клеток, которые должны начать двигаться, потеряв "опору").
>>> никто не запрещает вам обработать клик игрока
В случае "двух режимов" - как раз и будет запрещать. Потому что предлагаемый уже DrawGrid такого физически не умеет, у него не существует клетки "между клеток".

19-05-2019 08:24 | Комментарий к предыдущим ответам
Такая программа проста и на свою разработку не потребует от вас много времени. Зато отлично проиллюстрирует работу массива "состояния игры". Только напишите сами, без копипаста (даже картинок).

19-05-2019 08:18 | Вопрос к автору: запрос дополнительной информации
Вы сможете написать программу игры "крестики и нолики"?
Без анимации, на одном Delphi, используя DrawGrid?

19-05-2019 07:58
Den Sarych , Я с Вами полностью согласен. Я не говорю что бы вообще отказаться от двух мерного массива и у меня изначально строится


    for x:= 3 to 17 do
      for y:= 0 to 3 do begin
      P[x,y] := -1;
    end;
    for x:= 3 to 17 do
      for y:=18 to 20 do begin
      P[x,y] := -1;
    end;
    for x:= 0 to 2 do
      for y:= 3 to 17 do begin
      P[x,y] := -1;
    end;
    for x:= 18 to 20 do
      for y:= 3 to 17 do begin
      P[x,y] := -1;
    end;
   

А вот как быть с анимацией? Как запустить массив клеток в двухмерном массиве пока не разобрался.

19-05-2019 05:32 | Вопрос к автору: запрос дополнительной информации
>>>Мне кажется что двухмерный массив - не вариант
  Хм... . Массив нужен не столько для отрисовки, сколько для запоминания "состояния" игры.
  Попробуйте на время оставить Asphyre.
  Давайте на более простом примере, попытаемся выяснить ценность двумерного массива и назначение "состояния" игры?

19-05-2019 04:55
для Python
  Вы наверное и сами догадались, что формулировки "Вся игра будет находиться всего в двух режимах" и "Вариант 3 не очень интересен, ... я бы реализовал более сложный вариант игры, в котором клетки могут одновременно двигаться и принимать сообщения.", с точки зрения программирования, если обособлены уровни "логики игры", "механики отображения" и "взаимодействия с игроком", практически идентичны. Но согласитесь, насколько, более понятной для новичка и полезной для отладки, выглядит первая формулировка.
  Поясню. Не "клетки могут принимать сообщения", а уровень "взаимодействия с игроком" принимает сообщения от игрока. Уровень "логики" определяет, что означает этот клик, затем вычисляет "исходное" и "целевое" состояние. А уровень "механики отображения" просто показывает изменение состояния игры.
  Например, вы делаете игру "пятнашки". По клику игрока, фишка, со скоростью черепахи, начинает перемещаться. Т.е. уровень "логики" определил "исходное" (что было) и "целевое" (что будет) состояния, а уровень "механики" пытается отобразить переход из одного состояния в другое. Для отладки, полезнее досмотреть это переползание до конца. Но никто не запрещает вам обработать клик игрока и в процессе переползания фишки. В этом случае, уровень "логики" перекинет состояние игры в новое, а "механика" отобразит переползание фишки уже в обратную сторону. ;-)

18-05-2019 18:59
Python, спасибо что откликнулись. Мне кажется что двухмерный массив - не вариант или выполнение выставлено не правильно.

18-05-2019 00:09
Сперва хочу посоветовать статью Антона Григорьева Клетчатые игры
Ну а потом уже - свои соображения по этому поводу. Вариант 3 не очень интересен, так как выглядит некрасиво (игрок лишается возможности действовать, пока идёт анимация, это во всех играх просто вымораживает и практически всегда приводит к потере интереса к игре, знаю как по собственному опыту, так и по опыту других игроков, включая тех, что стримит игры на ютубе... конечно, не такие простые, как брикшутер, но и намного более сложные игры грешат тем же самым). Потому, я бы релизовал более сложный вариант игры, в котором клетки могут одновременно двигаться и принимать сообщения. Конечно, реализация будет существенно сложнее, зато интереснее.
Я пока сходу не смог придумать оптимального алгоритма реализации, пока в голову приходит только вариант, при котором игровое поле (клеточное) будет знать, что на одной виртуальной клетке может быть вообще говоря до четырёх физических клеток (это если допускать движение и по горизонтали и по вертикали, при движении только по вертикали - только две физические клетки), будет уметь определять, какие клетки являются соседями при любом их движении (например, если игрок кликает по движущемуся столбцу, но при этом левый соседний столбец тоже двигается, а правый - неподвижен, это не должно приводить к ошибкам) и рассылать сообщения только соседям (например, при уничтожении клетки, она должна разослать всем соседям того же цвета сообщение, чтобы они тоже уничтожились). Возможно, когда придёт в голову разумный вариант, я реализую и отпишусь тут.

17-05-2019 11:37
Den Sarych, большое спасибо, буду пробовать. Сейчас пробую на движке Asphyre. Пытался на DelphiX соорудить при помощи спрайтов, опять же с массивом не смог разобраться (спайт ушел со своего места и капец). В Asphyre пытаюсь остановить тайл во время движения, типа

var P: array [0..50,0..50] of integer;
......................
  with Tile[openX,openY] do begin
  if (X>=230) and P[openX-1,openY]<> 5 then
      X:= X-5;
  end;

не останавливаясь проходит мимо.

17-05-2019 02:34
>>>Как вообще там всё строится?
Разделите разработку вашей игры на три этапа:
1. Разработка "логики игры";
2. Разработка "механики передвижений" и собственно анимации;
3. Добавление к анимации логики игры.

  1. Вообще, клеточные игры, внутри программы представляются некоторым двумерным полем значений. Для простоты, будем считать его  прямоугольным, с размером X на Y. Соответственно значения будут храниться в массиве A[1..x, 1..y]. Этот массив будем называть "состоянием игры" или "массивом состояний". В интерфейсе игры, отображается "игровое поле", разделённое на клетки, причём каждой клетке "игрового поля" соответствует значение "массива состояний". Например, значения могут быть такие: "пустая", "подвижная", "неподвижная", "центральная". Дополнительно, для всех, кроме "пустой", может быть указан "тип рисунка клетки".
  При действиях игрока (клике на клетке), игра должна "отреагировать". Т.е. из начального состояния A (читай, значений массива) перейти в новое состояние B. Другими словами, на основании значений массива A, создаётся массив B, с внесёнными в него изменениями. После этого "игровое поле" очищается и заполняется картинками соответствующими значениям массива B.
  Собственно вся логика игры и заключается в правилах перевода "состояний игры" из одного в другое, да распознавании "выигрышного состояния".
  Чтобы отладить логику игры, удобнее всего написать программку-прототип, "игровое поле" в которой, будет изображать обычный DrawGrid. Здесь не нужно никакой анимации. Клик на клетке и игра перескакивает из одного состояния в другое, а "игровое поле" перерисовывается. И картинки, и "массив состояний", мы потом используем в окончательном варианте игры, но уже на этом этапе игра будет вполне играбельна.
 
  2. "Механика передвижений" - это программирование отображения "клеток" на "игровом поле". Например, их может быть три типа: "неподвижная", "передвигающаяся", "исчезающая". На основе какой технологии (TShape, DelphiX, ...) вы будете делать  перемещение квадратика по экрану не столь важно. Важно чтобы, именно "квадратики", и именно "красиво ползали" по "игровому полю" от одного фиксированного места (клетки) до другого.
  Обязательно сделайте отдельный прототип этой программы. Пока без "логики игры", простое отображение и перемещение квадратика с картинкой.

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

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Однажды, в студеную зимнюю пору я из лесу вышел, был сильный ЧТО?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

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

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования