Форум программистов, компьютерный форум, киберфорум
Наши страницы
PascalABC.NET
Войти
Регистрация
Восстановить пароль
 
xlxndr
57 / 9 / 4
Регистрация: 14.06.2013
Сообщений: 124
1

Как корректно реализовать обработчик нажатия клавиши для массива объектов?

18.12.2015, 18:34. Просмотров 450. Ответов 3
Метки нет (Все метки)

Сделал программу движения шарика по нажатию клавиши:

Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
Program keyEvent; 
uses GraphABC, Events;  { подключение модулей } 
 
Type  Krug = class
private
      x,y,R: integer;     //поле
      col: color;
public
      Constructor Create(InitX, InitY, InitR: Integer; InitColor: Color);
      Procedure Keydown(key: integer);
      Procedure Hide;
      Procedure Draw;
      Procedure MoveByKeystroke;
end;
 
{МЕТОДЫ КЛАССА Krug}
Constructor Krug.Create(InitX, InitY, InitR: Integer; InitColor: Color);
begin
  x := InitX;
  y := InitY;
  R := InitR;
  col := InitColor;
end;
 
procedure Krug.Draw;  { процедура рисования круга } 
begin 
    SetPenColor(clWhite); SetBrushColor(col);  Circle(x,y,R); 
end; 
 
procedure Krug.Hide;  { процедура стирания круга } 
begin 
    SetPenColor(clWhite); SetBrushColor(clWhite);  Circle(x,y,R); 
end; 
 
procedure Krug.Keydown(key: integer);  { процедура обработки нажатия клавиш } 
begin 
    case key of
    VK_Left:    x:=x-1;  { влево } 
    VK_Right:   x:=x+1;   { вправо } 
    VK_Up:      y:=y-1;  { вверх } 
    VK_Down:    y:=y+1;   { вниз } 
    VK_Escape:  CloseWindow;  { закрыть окно } 
    end;
end; 
 
Procedure Krug.MoveByKeystroke;
begin
  Hide;
  OnKeyDown:=Keydown; //вызываем обработчик нажатия клавиши
  Draw;
end;
 
Const n = 100;
MaxX=600;
MaxY=400;
 
Var f:boolean;
    k:Krug;
    i:integer;
 
begin 
setWindowSize(MaxX,MaxY); 
k:=Krug.Create(100, 100, 30, clRed);
k.Draw;
 
lockdrawing;
f:=false;
repeat
k.MoveByKeystroke;
redraw;
sleep(10);
until f;
end.
Двигается.

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

Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
Program keyEvent; 
uses GraphABC, Events;  { подключение модулей } 
 
Type  Krug = class
private
      x,y,R: integer;     //поле
      col: color;
public
      Constructor Create(InitX, InitY, InitR: Integer; InitColor: Color);
      Procedure Keydown(key: integer);
      Procedure Hide;
      Procedure Draw;
      Procedure MoveByKeystroke;
end;
 
{МЕТОДЫ КЛАССА Krug}
Constructor Krug.Create(InitX, InitY, InitR: Integer; InitColor: Color);
begin
  x := InitX;
  y := InitY;
  R := InitR;
  col := InitColor;
end;
 
procedure Krug.Draw;  { процедура рисования круга } 
begin 
    SetPenColor(clWhite); SetBrushColor(col);  Circle(x,y,R); 
end; 
 
procedure Krug.Hide;  { процедура стирания круга } 
begin 
    SetPenColor(clWhite); SetBrushColor(clWhite);  Circle(x,y,R); 
end; 
 
procedure Krug.Keydown(key: integer);  { процедура обработки нажатия клавиш } 
begin 
    case key of
    VK_Left:    x:=x-1;  { влево } 
    VK_Right:   x:=x+1;   { вправо } 
    VK_Up:      y:=y-1;  { вверх } 
    VK_Down:    y:=y+1;   { вниз } 
    VK_Escape:  CloseWindow;  { закрыть окно } 
    end;
end; 
 
Procedure Krug.MoveByKeystroke;
begin
  Hide;
  OnKeyDown:=Keydown; //вызываем обработчик нажатия клавиши
  Draw;
end;
 
Const n = 100;
MaxX=600;
MaxY=400;
 
Var f:boolean;
    mas:Array [1..n] of Krug;
    i:integer;
 
begin 
 
for i:=1 to n do
begin
  MAS[i]:=Krug.Create(Random(MaxX),Random(MaxY),Random(20),clRandom);
  MAS[i].Draw;
end;
 
f:=false;
lockdrawing;
repeat
for i:=1 to n do
begin
  MAS[i].MoveByKeystroke;
  sleep(10);
end;
redraw;
sleep(100);
until f;
 
end.
Как это оптимизировать, чтобы двигались одинаково, сплошной картинкой?
И вопрос по первому листингу - почему при работе программы от шарика остается "шлейф" при движении???
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
18.12.2015, 18:34
Ответы с готовыми решениями:

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

Как сделать процедуру нажатия определённой клавиши в windows forms?
Как сделать процедуру нажатия определённой клавиши в windows forms?

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

Эмуляция нажатия клавиши
Хочу узнать, можно ли в "паскаль АБЦ нэт" осуществить эмуляцию нажатия какой...

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

3
capricornus CF
315 / 205 / 162
Регистрация: 08.12.2015
Сообщений: 853
18.12.2015, 20:58 2
Средство от шлейфа - увеличить на 1 пиксель круг стирающий.

Pascal
1
2
3
4
procedure Krug.Hide;  { процедура стирания круга } 
begin 
    SetPenColor(clWhite); SetBrushColor(clWhite);  Circle(x,y,R+1); 
end;
Добавлено через 5 минут
В комплекте с паскалем идет пример движения кучи объектов, посмотрите как организовано:
Кликните здесь для просмотра всего текста
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
uses ABCObjects,GraphABC,Utils;
 
const 
/// Количество графических объектов
  Count = 300;
/// Флаг ускорения анимации
  AnimationIsFast = True;
  
/// Возвращает случайный графический объект
function NewRandomABC: ObjectABC;
begin
  case Random(3) of
0: Result := new CircleABC(Random(WindowWidth-30)+10,Random(WindowHeight-30)+10,Random(10)+5,clRandom);
1: Result := new RectangleABC(Random(WindowWidth-30)+10,Random(WindowHeight-30)+10,Random(20)+10,Random(20)+10,clRandom);
2: Result := new StarABC(Random(WindowWidth-30)+10,Random(WindowHeight-30)+10,Random(20)+10,Random(10)+5,Random(4)+4,clRandom);
  end;
end;
 
/// Передвигает графический объект с отражением его от стенок
procedure Move(o: ObjectABC);
begin
  o.Move;
  if (o.Left<0) or (o.Left+o.Width>WindowWidth) then
    o.dx := -o.dx;
  if (o.Top<0) or (o.Top+o.Height>WindowHeight) then
    o.dy := -o.dy;
end;
 
begin
  Window.Title := 'Движущиеся объекты';
  if AnimationIsFast then
    LockDrawingObjects;
  for var i:=1 to Count do
  begin
    var m: ObjectABC := NewRandomABC;
    repeat
      m.dx := Random(-3,3);
      m.dy := Random(-3,3);
    until (m.dx<>0) and (m.dy<>0);
  end;
  var k := 1;
  while True do
  begin
    for var i:=0 to Objects.Count-1 do
      Move(Objects[i]);
    if AnimationIsFast then
      RedrawObjects;
    k += 1;
    Window.Title := Format('{0,5:f2}',k/Milliseconds*1000)+' кадров в секунду';
  end;
end.
1
xlxndr
57 / 9 / 4
Регистрация: 14.06.2013
Сообщений: 124
19.12.2015, 19:35  [ТС] 3
спасибо, но это немного не то... вопрос именно в обработчике по нажатию клавиши, а не просто движении... просто объекты и так двигаются прекрасно - без всяких динамических массивов.
0
capricornus CF
315 / 205 / 162
Регистрация: 08.12.2015
Сообщений: 853
21.12.2015, 08:01 4
Есть и обработчики:

Кликните здесь для просмотра всего текста
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
uses ABCObjects,GraphABC,Timers;
 
const 
  clPlayer = Color.BurlyWood;
 
var
  kLeftKey,kRightKey: boolean;
  kSpaceKey: integer;
  /// Игрок
  Player: RectangleABC;
  /// Таймер движения врагов
  t: Timer;
  /// Флаг конца игры
  EndOfGame: boolean;
  /// Количество неигровых объектов
  StaticObjectsCount: integer;
  /// Счетчик выигрышей
  Wins: integer;
  /// Счетчик проигрышей
  Falls: integer;
  /// Информационная строка
  InfoString: RectangleABC;
  /// Сообщение в начале игры
  NewGame: RoundRectABC;
 
type
  KeysType = (kLeft,kRight);
  
  /// Класс пули
  Pulya = class(CircleABC)
  public
    constructor Create(x,y: integer);
    procedure Move; override;
  end;
  
  /// Класс врага
  Enemy = class(RectangleABC)
  public
    constructor Create(x,y,w: integer);
    procedure Move; override;
  end;
 
constructor Pulya.Create(x,y: integer);
begin
  inherited Create(x,y,5,clRed);
  dx := 0; 
  dy := -5;
end;
 
procedure Pulya.Move; 
begin
  inherited Move; 
  if Top<0 then
    Visible := False;
  for var j:=StaticObjectsCount to Objects.Count-1 do
    // При столкновении пуля и объект становятся невидимыми
    if (Objects[j]<>Self) and Intersect(Objects[j]) then
    begin
      Objects[j].Visible := False;
      Visible := False;
    end;
end;
 
constructor Enemy.Create(x,y,w: integer);
begin
  inherited Create(x,y,w,20,clRandom);
  if Random(2)=0 then
    dx := 5
  else dx := -5;
  dy := 0;
end;
 
procedure Enemy.Move; 
begin
  if Random(2)<>0 then 
    Exit;
  if Random(10)=0 then 
    dy := 5;
  if (Left<0) or (Left+Width>Window.Width) or (Random(30)=0) then
    dx := -dx;
  inherited Move;
  if dy<>0 then 
    dy := 0;
  if Top>Window.Height-50 then
    EndOfGame := True;
end;
 
/// Количество врагов
function NumberOfEnemies: integer;
begin
  Result := 0;
  for var i:=0 to Objects.Count-1 do
    if Objects[i] is Enemy then
      Result += 1;
end;
 
/// Создание игрока и врагов
procedure CreateObjects;
begin
  Player := new RectangleABC(280,WindowHeight-30,100,20,clPlayer);
  for var i:=1 to 100 do
  begin
    var r1 := new Enemy(Random(WindowWidth-50),40+Random(10),50);
    r1.TextVisible := True;
    r1.Number := i;
  end;
end;
 
/// Разрушение игрока и врагов
procedure DestroyObjects;
begin
  for var i:=Objects.Count-1 downto StaticObjectsCount do
    Objects[i].Destroy;
end;
 
/// Перемещение врагов
procedure MoveObjects;
begin
  for var i:=StaticObjectsCount+1 to Objects.Count-1 do
    Objects[i].Move;
end;
 
/// Удаление уничтоженных объектов
procedure DestroyKilledObjects;
begin
  for var i:=ObjectsCount-1 downto StaticObjectsCount+1 do
    if not Objects[i].Visible then
      Objects[i].Destroy;
end;
 
/// Обработчик нажатия клавиши
procedure KeyDown(Key: integer);
begin
  case Key of
vk_Left:  kLeftKey := True;
vk_Right: kRightKey := True;
vk_Space: if kSpaceKey=2 then kSpaceKey := 1;
  end;
end;
 
/// Обработчик отжатия клавиши
procedure KeyUp(Key: integer);
begin
  case Key of
vk_Left:  kLeftKey := False;
vk_Right: kRightKey := False;
vk_Space: kSpaceKey := 2;
  end;
end;
 
/// Изменение информационной строки
procedure ChangeInfoString;
begin
  InfoString.Text := 'Врагов: '+IntToStr(NumberOfEnemies)+'      Побед: '+IntToStr(Wins)+'      Поражений: '+IntToStr(Falls);
end;
 
/// Обработчик нажатия символьной клавиши
procedure KeyPress(Key: char);
begin
  if (Key in ['G','П','g','п']) and EndOfGame then
  begin
    NewGame.Visible := False;
    EndOfGame := False;
    t.Start;
    CreateObjects;
    kSpaceKey := 2;
    kLeftKey := False;
    kRightKey := False;
  end;
end;
 
/// Обработчик отжатия мыши
procedure MouseUp(x,y,mb: integer);
begin
  if NewGame.PTInside(x,y) then
    KeyPress('G');
end;
 
/// Обработчик таймера
procedure TimerProc;
begin
  if kLeftKey and (Player.Left>0) then
    Player.MoveOn(-10,0);
  if kRightKey and (Player.Left+Player.Width<WindowWidth) then
    Player.MoveOn(10,0);
  if kSpaceKey=1 then
  begin
    new Pulya(Player.Left+Player.Width div 2,Player.Top-10);
    kSpaceKey := 0;
  end;
  MoveObjects;
  DestroyKilledObjects;
  RedrawObjects;
  ChangeInfoString;
  var n := NumberOfEnemies;
  // Страховка от случая, когда процедура таймера выполняется одновременно в нескольких потоках
  if n=0 then
    EndOfGame := True;
  if EndOfGame then
  begin
    if t.Enabled=False then Exit;  
    t.Stop;
    if n>0 then
      Falls += 1
    else Wins += 1;
    NewGame.Visible := True;
    DestroyObjects;
    ChangeInfoString;
    RedrawObjects;
  end;
end;
 
begin
  Window.Title := 'Стрелялка';
  Window.IsFixedSize := True;
  ClearWindow(clBlack);
  LockDrawingObjects;
  EndOfGame := True;
  InfoString := new RectangleABC(0,0,Window.Width,38,Color.DarkBlue);
  InfoString.Bordered := False;
  InfoString.FontColor := clWhite;
  InfoString.TextScale := 0.9;
  
  var zz := 100;
  NewGame := new RoundRectABC(zz,200,400,200,30,Color.Violet);
  NewGame.Center := Window.Center;
  NewGame.Text := 'G - Новая игра';
  StaticObjectsCount := Objects.Count;
  ChangeInfoString;
  RedrawObjects;
 
  OnKeyDown := KeyDown;
  OnKeyPress := KeyPress;
  OnKeyUp := KeyUp;
  OnMouseUp := MouseUp;
 
  t := new Timer(1,TimerProc);
end.


Добавлено через 11 часов 28 минут
Обработка изменения координат производится по таймеру, чтобы одновременно с изменением координат не происходило параллельно других процессов.
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
21.12.2015, 08:01

Обработка нажатия клавиши в unit
Есть главная программа: program test; uses MenuFile begin OnKeyDown :=...

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

WTL как Сделать Мультиселект? Пересылка сообщений Обработчик события нажатия клавиши
Hi ALL! Сабж в том, что я ни разу в глаза не видел WTL и вообще не вкурю...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru