forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   Проекты на MidletPascal (http://forum.boolean.name/forumdisplay.php?f=88)
-   -   The Maze (http://forum.boolean.name/showthread.php?t=4621)

Tadeus 07.12.2008 16:42

Ответ: The Maze
 
Товарищи, а где можно популярно и доходчиво почитать про ray-casting? Все никак не могу с ним разобраться :)

Romanzes 07.12.2008 18:15

Ответ: The Maze
 
Вот, если кто хочет, покурите исходники оригинального Wolfenstein 3D. Сам я в них разобраться не могу, потому что пока не знаю C++. А я пока займусь переносом двига от abcdef на java. Все-таки я считаю, что нужно юзать png картинки, а не bmp.

abcdef 07.12.2008 19:28

Ответ: The Maze
 
Romanzes - в принципе без разницы в каком формате картинки. Помнится что jar-файл поворота картинки был даже больше, чем версия на паскале. Это все из-за файла Gordon.png - он плохо сжимался. А bmp из-за малой палитры лучше упаковывался. Все-таки лучше оставить bmp, потому что с ним легче работать и после загрузки картинок (безразлично в каком формате) остаются только массивы пикселов.
___
Cliffe Snake - текстурирование пола и потолка в 2 раза понизит скорость программы, но есть способ зарисовки удаленным задним фоном зданий/гор/неба, (когда-то придумывал, но он будет работать только c drawRGB),состоит в том что: в массив экрана вводим другой массив со смешением позиции: остаток от деления угола зрения на ширину экрана, таким образом получаем плавную прокрутку заднего фона.. смотрится довольно эффективно,..
___
Посмотрел "в закромах" нашел алгоритм, который когда-то делал для расчетов и рисования спрайтов. Выкладываю чтоб не изобретали велосипед. Возможно где-нибудь будет неточности, переписывал не проверяя..
___
Код:

function intSqrt(v : integer) : integer;
{Вычисление квадратного корня}
var
  result, tmp : integer;
  low, high : integer;
  i : integer;
begin
  if (v > 1) then
  begin
    low := v;
    high := 0;
    result := 0;
    for i := 0 to 15 do
    begin
      result := result+result;
      high := (high shl 2) or ((low shr 30) and $03);
      low  := low shl 2;
      tmp  := result+result+1;
      if (high >= tmp) then
      begin
        inc(result);
        high := high-tmp;
      end;
    end;
    if (v-(result*result) >= (result - 1)) then  inc(result);
    intSqrt := result;
  end
    else intSqrt := abs(v);
end;


procedure sprites;
const
  scalNum = 7000;  {масштабный коофициент для спрайтов}
var
  sp : tSprite;
  dx,dy,rx,ry : integer;
  i,j,scale,r,ycent, xcent : integer;
var  {- Рисование линии заданной высоты: с y1 до y2 -}
  yyy,y1,y2,offs,coof,yo,imgOffs,color : Integer;
begin
  ycent := screenHeight shr 1;
  xcent := screenWidth shr 1;
  for i := 0 to MaxSprites-1 do
  begin
    {Найдем расстояние до спрайта}
    dx := sprite[i].x - px;
    dy := sprite[i].y - py;
    sprite[i].dist :=intSqrt(dx*dx+dy*dy); {Определение расстояния между двумя точками}
    {Расчет луча для центра спрайта}
    rx := trunc(dx*costab[angle] + dy*sintab[angle]);  {Поворачиваем dx,dy на}
    ry := trunc(dy*costab[angle] - dx*sintab[angle]);  {угол зрения игрока}
    if (rx < 0) then  sprite[i].ray :=-1000          {спрайт вне зоны видимости}
    else
    begin    {Расчет луча для центра спрайта}
      if (rx > 0) then  ray := xcent + trunc((xcent*ry)/(rx*tan30))
        else  ray := xcent + trunc((xcent*ry)/tan30);
      {найдем положение спрайта относительно нас}
      if (abs(dx) >= abs(dy))  then
      begin
        if dx > 0 then
        begin
          if dy > 0 then  Racurs := 0
            else  Racurs := 7;
        end else
        begin
          if dy > 0 then  Racurs := 3
            else  Racurs := 4;
        end;
      end
        else
        begin
          if dx > 0 then
          begin
            if dy > 0 then  Racurs := 1
              else  Racurs := 6;
          end else
          begin
            if dy > 0 then  Racurs := 2
              else  Racurs := 5;
          end;
        end;
    end;
  end;
  {Сортировка спрайтов по удаленности}
  for i := 0 to MaxSprites-1-1 do
    for j := i+1 to MaxSprites-1 do
      if sprite[i].dist < sprite[j].dist then
      begin
        sp := sprite[i];  sprite[i] := sprite[j];  sprite[j] := sp;
      end;

  {логика работы и вывод спрайтов на экран}
  for i :=0 to MaxSprites-1 do
  begin
    {logic}
    анимация-высчитываем номер картинки: imgOffs := номер_картинки*64*64
    где (64*64 - размер одной картинки)
    .....
    {logic-end}
    {outToScreen}
    {Вывод спрайтов на экран если они попадают в зону видимости}
    scale := scalNum div (sprite[i].dist+1);  {масштаб изображения}
    r := sprite[i].ray - (scale shr 1);    {по обе стороны от середины}
    for j := 1 to scale do
    begin
      if (r>=0) and (r<=screenWidth-1) then {если попадаем в экран и}
      if (scale>screenDist[r]) then    {если ближе чем стена, то вывести}
      begin
        {---------------------- Текстурирование линии ----------------------}
        offs := imgOffs + ((j shl 6) div scale);
        y1  := (screenHeight-scale) shr 1;
        y2  := y1+scale;
        if y2 > screenHeight-1 then  y2 := screenHeight-1;
        coof := (63*256) div scale;
        yo := 0;
        for yyy := y1 to y2 do
        begin
          if yyy >= 0 then
          begin
            color := data[offs+((yo shr 8) shl 6)];
            if color <> 0 then begin setColor(...); plot(r,yyy); end;
          end;
          inc(yo, coof);
        end;
        {-------------------------------------------------------------------}
      end;
      inc(r);                            {следующий луч}
    end;
    {outToScreen-end}
  end;
end;


Cliffe Snake 08.12.2008 15:48

Ответ: The Maze
 
Вложений: 1
Вот подкрутил радарчик, исправил текстуры, добавил небо. Полный список изменений смотрите в ReadMe.txt :)

Romanzes 08.12.2008 21:25

Ответ: The Maze
 
Цитата:

Сообщение от Tadeus (Сообщение 91824)
Товарищи, а где можно популярно и доходчиво почитать про ray-casting? Все никак не могу с ним разобраться :)

Только что нашел туториал по рэй-кастингу на английском языке: http://www.permadi.com/tutorial/raycast/. Сейчас буду разбираться.

abcdef 09.12.2008 00:59

Ответ: The Maze
 
Вложений: 1
Cliffe Snake - да,да задний фон примерно так как ты сделал.. но немножко упростил, выглядит так:
Код:

  drawimage(sky,-((angle+angle) mod 360),0);
  drawImage(floor,0,h2);
  raycast;

картинка sky высотой в пол-экрана (64). и длинной 360+ширина_экрана, где кусочек 360..360+ширина_экрана совпадает с изображением в позиции 0..ширина_экрана.
___
Оч. неудобно что MIDletPascal не хочет делать длинные массивы, правильная идея сделать двухмерный :) но думаю на java быстрее будет делать одномерным..
___
переделал программку с учетом предложений Cliffe Snake
___
давайте для оптимальности будем делать так:
1. вычисления real заменять Lib_mathmp.class.
2. картинки желательно в bmp-формате, и при необходимости png, другие форматы лучше не использовать т.к. не все телефоны их будут поддерживать.
3. карты записывать в текстовом виде, где кубик стены записывается числом, здесь же будем описывать спрайты.

Cliffe Snake 09.12.2008 04:43

Ответ: The Maze
 
Цитата:

Сообщение от abcdef (Сообщение 91885)
Cliffe Snake - да,да задний фон примерно так как ты сделал.. но немножко упростил, выглядит так:
Код:

  drawimage(sky,-((angle+angle) mod 360),0);
  drawImage(floor,0,h2);
  raycast;

картинка sky высотой в пол-экрана (64). и длинной 360+ширина_экрана, где кусочек 360..360+ширина_экрана совпадает с изображением в позиции 0..ширина_экрана.

При такой реализации на экране 240x320 изображение смазывается.
Мой способ отображения "неба" более универсален, так как не зависит от размера экрана. :p :)

abcdef 09.12.2008 09:33

Ответ: The Maze
 
длина картинки заднего фона расчитывается так: угол обзора 60 градусов, равны ширине экрана, значит всего этих экранов будет 6 плюс добавочный, получается длина_картинки = ширина_экрана*7.
запускал на motorola V3i повисло, пришлось уменьшить data [0..6,0..4096] of integer;

Cliffe Snake 09.12.2008 17:54

Ответ: The Maze
 
Цитата:

Сообщение от abcdef (Сообщение 91888)
длина картинки заднего фона расчитывается так: угол обзора 60 градусов, равны ширине экрана, значит всего этих экранов будет 6 плюс добавочный, получается длина_картинки = ширина_экрана*7.

По моим вычислениям выходит, что 360 градусов равны 1080 пикселям
(то есть 1 градус = 3 пикселям)
PHP код:

//....
drawimage(nebo,angle*(-3),0);
drawimage(nebo,angle*(-3)+360,0);
drawimage(nebo,angle*(-3)+720,0);
drawimage(nebo,angle*(-3)+1080,0);
raycast;
//.... 

Dlina текстуры неба=90*n // где n=[1..12]
Кол-во повторений drawimage со двигом на Dlina = 1080/Dlina+1
Проверенно, 100% работает не зависимо от экрана.
Цитата:

Сообщение от abcdef (Сообщение 91888)
запускал на motorola V3i повисло, пришлось уменьшить data [0..6,0..4096] of integer;

Да... надо будет подсчитать сколько хипа хавает одна текстура..

abcdef 10.12.2008 00:36

Ответ: The Maze
 
Вложений: 1
Cliffe Snake - спорим об одном и том же, хотя по идее можно обойтись и картинкой шириной с экран.. нужно как можно более минимизировать кол-во вызовов графических функций.
Текстуры лучше представить одним файлом, на подобии вертикальной киноленты, т.о. будем экономить на каждом файле более 1кб из счет заголовка и палитры, кроме того большой файл упаковывается лучше, чем несколько маленьких. кол-во текстур нужно сократить и подгружать их по ходу игры, например при входе в комнату, но это уже в конце, когда все будет готово..
___
Интересно как справиться с программой средствами MIDletPascal, а иначе переписал бы за час на java..
Ранее выложил всю необходимую математику спрайтов, кто-нить уже сделал живых человечков? логику можно сделать такой: если догнал - уменьшаются жизни, а еще довольно неплохо смотриться метание огненными шарами (как в DOOM), шар - тот-же спрайт (направление движения (dx,dy) как у игрока в момент создания), который деинициализиреутся когда столкнется с каким-либо предметом.
Массив со спрайтами наполовину пуст, для генерации всевозможных дополнительных спрайтов. отработавшие спрайты либо превращаются в статические либо помечаются как пустые и свободные..
___
p.s. выкладываю редактор спрайтов/текстур для MSDOS-Wolfenshtein3D скопировать в папку с программой и запускать, есть возможность сохранения изображений в формате gif.

Trazzy 10.12.2008 07:25

Ответ: The Maze
 
Вижу, я немного не в тему пишу, еще про maze. Но пдскажите, пожалуйста, как в maze3d сделать так чтоб когда поварачиваешся влево/вправо не поварачивалась и карта (при этом меняются координаты х, у, что очень мешает узнаванию местонахождения на карте). Если не трудно выложите пример в зипе или хотябы просто листинг. Заранее благодарен...

abcdef 10.12.2008 09:10

Ответ: The Maze
 
поворот карты, своего рода оптимизация, иначе б в основном алгоритме нужно было рассматривать 4е случая. Получить координаты можно если запомнинать поворот относительно начального, а затем временные_х_у поворачивать обратно

Trazzy 12.12.2008 07:10

Ответ: The Maze
 
Я в мидлетпаскале относительно не долго, и теоретически знаю как это делается, а на деле чет не выходит. Можно пример?

abcdef 12.12.2008 21:22

Ответ: The Maze
 
Вложений: 1
Добавил алгоритм спрайтов, нужно оптимизировать и добавить логику, тогда будет хорошая игрушка. Подобных программ на MP не видел.. Кто возьмется делать логику? у кого есть интересные идеи?
__
p.s. ArtikZ - MIDletPascal это не лучший пособ для первого языка программирования, много ситуаций компиляции и проверки синтаксиса программы не поддается здравому смыслу, например при разработке спрайтов, если они были в записях record, то неправильно считался один из параметров. и если в массивах, то нельзя использовать последний элемент,
алгоритм поворота направо t:=x;x:=y;y:=29-t; налево t:=y;y:=x;x:=29-t; смотри какой угол и поворачивай в цикле обратно..

abcdef 14.12.2008 10:21

Ответ: The Maze
 
несколько замечаний по использованию вычислений в fixed-point real: числа с фиксированной точкой можно напрямую умножать или делить (если real в делимом, но не наоборот) на integer, а также складывать или вычитать два real-числа обычным сложением или вычитанием, во всех остальных случаях вычисления проводить только через библиотеку, а integer приводить к типу real через fIntToReal


Часовой пояс GMT +4, время: 18:50.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot