rotatable isometric image

Game development specific discussions.
BasicCoder2
Posts: 3394
Joined: Jan 01, 2009 7:03

rotatable isometric image

Postby BasicCoder2 » Sep 29, 2018 19:21

The program creates a list of 3d points abs3D()
The program requires these two images to be downloaded and resaved as bitmaps ambulance4.bmp and top2.bmp respectively.
Image
Image
The list of 3d points abs3D() are rotated by some angle into the rot3D() array and then projected onto a 2d bitmap image.
This bitmap image is then PUT onto the display at the isometric position of the ambulance's 2D position.
The two ambulances use the same set of absolute points to create an image but are rotated by their own angles and have their own 2d positions.
One ambulance is controlled by the arrow keys and the other is controlled by the ASDW keys.
The reason for the TANK label is because it was going to be a tank vehicle but I haven't got around to writing the code to draw a tank.
So it is meant to be a tank image which I will hopefully remedy later.

EDIT: Code modified with suggestions made in next two posts.


Code: Select all

const ScrW = 1280
const ScrH = 480

const imgW = 100
const imgH = 100

'some useful defines
Const Pi = 4 * Atn(1)
Dim Shared As single TwoPi = 8 * Atn(1)
Dim Shared As single RtoD = 180 / Pi   ' radians * RtoD = degrees
Dim Shared As single DtoR = Pi / 180   ' degrees * DtoR = radians

screenres ScrW,ScrH,32
color rgb(0,0,0),rgb(155,155,255):cls

'===========    make cube   ========================
dim shared as any ptr cube1
cube1 = imagecreate(32,33,rgb(255,0,255))
dim as integer x1,y1,x2,y2
for i as integer = 1 to 9
    read x1,y1,x2,y2
    line cube1,(x1,y1)-(x2,y2),rgb(0,0,0)
next i
paint cube1,(10,7),rgb(204,167,98),rgb(0,0,0)
paint cube1,(23,20),rgb(98,49,49),rgb(0,0,0)
paint cube1,(8,19),rgb(158,98,68),rgb(0,0,0)

data 16,0,31,8,  31,8,16,15,  15,16, 0,8,  0,8,15,0
data 31,24,16,32,  15,32,0,24,  31,8, 31,24,  15,16,15,32,  0,8,0,24
'======================================================

dim shared as any ptr ambulance
ambulance = imagecreate(61,47)
bload "ambulance4.bmp",ambulance

dim shared as any ptr top
top = imagecreate(110,31)
bload "top2.bmp",top

dim shared as any ptr image        'hold a image of rotated points
image = imagecreate(imgW,imgH)

type Point3D
    x as single
    y as single
    z as single
    c as ulong
end type

sub plot3D(x as single,y as single,z as single, c as ulong)
    'circle ( (x-y) + imgW/2, (x+y)/2 + z + imgH/2 ),1,c,,,,f
    pset image,( (x-y) + imgW/2, (x+y)/2 + z + imgH/2 ),c
end sub

'dodicat's fast qsort of points according to distance
Sub QsortZ(array() As Point3D,begin As Long,Finish As Ulong)
    Dim As Long i=begin,j=finish
    Dim As Point3D x =array(((I+J)\2))
    While I <= J
        While array(I).z > X .z:I+=1:Wend
        While array(J).z < X .z:J-=1:Wend
        If I<=J Then Swap array(I),array(J): I+=1:J-=1
    Wend
    If J >begin Then QsortZ(array(),begin,J)
    If I <Finish Then QsortZ(array(),I,Finish)
End Sub

type TANK
    as single  x          'x position of center of disc
    as single  y          'y position of center of disc
    as single  dx         'change in x position per cycle
    as single  dy         'change in y position per cycle
    as single  v          'speed restricted to -1.0 to +1.0
    as single  angle     'direction in degrees
end type

dim shared as integer MAX_DOTS
dim shared as integer TOT_DOTS
MAX_DOTS = 50000

dim shared as TANK t1,t2
t1.x = 0
t1.y = 0
t1.angle = 0


t2.x = 100
t2.y = 200
t2.angle = 0



'now dimension array of absolute position of points and array of rotated points
dim shared as Point3D abs3D(MAX_DOTS)  'absolute positions
dim shared as Point3D rot3D(MAX_DOTS)  'relative positions after any rotation

dim as ulong v,v2
dim as integer flag,x,y,z


' ============   create absolute point positions for ambulance  ==========
'edge data to draw back,top and bottom pixels of object
dim as integer edgeX(0 to 110),edgeY(0 to 110)
for i as integer = 0 to 110
    read edgeX(i),edgeY(i)
next i

for j as integer = 1 to 46
    flag = 0
    for i as integer = 0 to 60
        v = point(i,j,ambulance)
        if v <> rgb(255,0,255)  then
            abs3D(TOT_DOTS).x = i  - imgW/4
            abs3D(TOT_DOTS).y = 15
            abs3D(TOT_DOTS).z = j
            abs3D(TOT_DOTS).c = v
            if TOT_DOTS < MAX_DOTS then TOT_DOTS = TOT_DOTS + 1           
        end if
    next i
next j

for j as integer = 0 to 46
    for i as integer = 0 to 60
        v = point(i,j,ambulance)
        if v <> rgb(255,0,255) then
            abs3D(TOT_DOTS).x = i   - imgW/4
            abs3D(TOT_DOTS).y = -15
            abs3D(TOT_DOTS).z = j
            abs3D(TOT_DOTS).c = v
            if TOT_DOTS < MAX_DOTS then TOT_DOTS = TOT_DOTS + 1
        end if
    next i
next j

for i as integer = 0 to 109
    for y as integer = -15 to 15
        abs3D(TOT_DOTS).x = edgeX(i) -imgW/4
        abs3D(TOT_DOTS).y = y
        abs3D(TOT_DOTS).z = edgeY(i)
        abs3D(TOT_DOTS).c = point(i,y+15,top)
        if TOT_DOTS < MAX_DOTS then TOT_DOTS = TOT_DOTS + 1
    next y
next i

'=====================================================================

sub moveTank(t as TANK)
    t.dx = cos(t.angle*DtoR) * t.v
    t.dy = sin(t.angle*DtoR) * t.v
    t.x = t.x + t.dx
    t.y = t.y + t.dy
end sub

sub rotatePoints(tt as TANK)  'rotates points by tt.angle
   
    dim as single x,y,z,scale

    'rotate
    dim as single cosAngleX,sinAngleX,angleX
    dim as single cosAngleY,sinAngleY,angleY
    dim as single cosAngleZ,sinAngleZ,angleZ

   
    angleZ = tt.angle*DtoR    'angle to rotate points
    cosAngleZ = cos(angleZ)
    sinAngleZ = sin(angleZ)
    scale = 1/sqr(2)
   
    for i as integer = 0 to TOT_DOTS - 1  'rotate each point
        'rotate z axis
        x = abs3D(i).x
        y = abs3D(i).y
        z = abs3D(i).z
        rot3D(i).x = ((cosAngleZ * x) - (sinAngleZ * y))*scale
        rot3D(i).y = ((sinAngleZ * x) + (cosAngleZ * y))*scale
        rot3D(i).z = z*0.5
        rot3D(i).c = abs3D(i).c
    next i
   
    'sort by distance along z axis
    '***dodisort***
    Qsortz(rot3D(),Lbound(rot3D),TOT_DOTS - 1)
    'Qsortz(rot3D(),Lbound(rot3D),Ubound(rot3D))

   
end sub

sub drawSprite(t as TANK)
   
    'clear image
    line image,(0,0)-(imgW-1,imgH-1),rgb(255,0,255),bf
    line image,(0,0)-(imgW-1,imgH-1),rgb(0,0,0),b  'show edge of image
   
    rotatePoints(t)  'rotate abs3D() points by t.angle to produce rot3D() points
   
    'draw rotated points onto image bitmap
    for i as integer = 0 to TOT_DOTS - 1
        plot3D(rot3D(i).x, rot3D(i).y, rot3D(i).z, rot3D(i).c)
    next i
   
    'cartesian to isometric coordinates of image
    dim as single tempX = (t.x - t.y) + 640 - imgW/2
    dim as single tempY = (t.x + t.y) / 2 + 30 - imgH/2
   
    'put rotated image on display
    put (tempX,tempY),image,trans
   
end sub

sub drawPoints()
    screenlock
    cls
    'draw isometric cubes
    for y as integer = 0 to 24
        for x as integer = 0 to 24
            put ( (x*16-y*16) + SCRW/2 - 16, (x*16+y*16)/2 + 0 + 30 ),cube1,trans
        next x
    next y
   
    moveTank(t1)
    drawSprite(t1)  'draw rotated pixels onto image and place on screen
   
    moveTank(t2)
    drawSprite(t2)  'draw rotate pixels onto image and place on screen
   
    locate 2,2
    print t1.angle,t2.angle,TOT_DOTS
   
    screenunlock()
end sub

dim as double now1
now1 = timer


do
   
    if timer - now1 > 0.01 then
        now1 = timer
       
        drawPoints()
       
        '==================================================
        'cursor keys to control tank1
        t1.v = 0
   
        if multikey(&H50) then t1.v = -2 'REVERSE
        if multikey(&H48) then t1.v =  2 'FORWARD
       
        'rotate around z axis
        if multikey(&H4D) then
            t1.angle = t1.angle + 1
            if t1.angle > 360 then t1.angle = t1.angle - 360
        end if
        if multikey(&H4B) then
            t1.angle = t1.angle - 1
            if t1.angle < 0 then t1.angle = t1.angle + 360
        end if
       
        '==================================================
        'ASDW keys to control tank2
        t2.v = 0
       
        if multikey(&H1F) then t2.v = -2 'REVERSE
        if multikey(&H11) then t2.v =  2 'FORWARD
       
        'rotate around z axis
        if multikey(&H20) then
            t2.angle = t2.angle + 1
            if t2.angle > 360 then t2.angle = t2.angle - 360
        end if
        if multikey(&H1E) then
            t2.angle = t2.angle - 1
            if t2.angle < 0 then t2.angle = t2.angle + 360
        end if
       
    end if
   
    sleep 2
   
loop until multikey(&H01)


sleep

'coordinates of back, top and front of side edge of ambulance image to join using colors in top2 bitmap
data 0,30, 0,29, 0,28, 0,27, 1,27, 1,26, 1,25, 1,24, 1,23, 1,22, 1,21, 1,20, 1,19, 1,18, 1,19, 1,18, 1,17, 1,16
data 1,15, 1,14, 1,13, 1,12, 1,11, 1,10, 1,9, 1,8, 1,7, 1,6, 1,5, 1,4, 1,3, 1,2, 2,1, 3,0
data 4,0, 5,0, 6,0, 7,0, 8,0, 9,0, 10,0, 11,0, 12,0, 13,0, 14,0, 15,0, 16,0, 17,0, 18,0, 19,0, 20,0, 21,0
data 22,0, 23,0, 24,0, 25,0, 26,0, 27,0, 28,0, 29,0, 30,0, 31,0, 32,0, 33,0, 34,0, 35,0, 36,0, 37,0, 38,0, 39,0
data 40,0, 41,0, 42,0, 43,0, 44,0
data 44,1, 45,2, 45,3, 46,4, 46,5, 47,6, 47,7, 48,8, 48,9, 49,10, 49,11, 50,12, 51,13, 52,14, 53,14, 54,15, 55,15
data 56,16, 57,16, 58,17, 58,18, 58,19, 58,20, 58,21, 58,22, 58,23, 58,24, 58,25, 58,26, 58,27, 59,27, 60,27, 60,28, 60,29, 60,30
Last edited by BasicCoder2 on Sep 30, 2018 6:54, edited 3 times in total.
badidea
Posts: 1417
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: rotatable isometric image - still has a bug

Postby badidea » Sep 29, 2018 20:41

Looking into it...

Three other things I noticed:
* Change dim as single now1 to dim as double now1 (weird problems on linux otherwise)
* Rotation speed and velocity depend on computer speed and/or compiler options
* 2nd 'tank' moves backwards when I expect forward [W]

I'm not sure yet, but it seems like you have one set of rot3D(...) which are used for both 'tanks'.
The rotation is a relative rotation? E.g. angle change compared to previous rotation.
Sorry, that can be it. abs3D --> rotation --> rot3D

If I disable ***dodisort*** the problem disappears
dodicat
Posts: 5892
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: rotatable isometric image - still has a bug

Postby dodicat » Sep 29, 2018 21:27

If you sort within the array range of i it seems OK

Qsortz(rot3D(),Lbound(rot3D),TOT_DOTS - 1)
BasicCoder2
Posts: 3394
Joined: Jan 01, 2009 7:03

Re: rotatable isometric image

Postby BasicCoder2 » Sep 29, 2018 22:10

Thanks badidea and dodicat for testing the code and your suggestions.
I will have to find a simple way to solve the frames per second issue for different compiles or computers.
It seems simpler with Javascript which I have been trying to learn where you simply set the milliseconds with

Code: Select all

setInterval(draw, 10);  // for 10 milliseconds
Last edited by BasicCoder2 on Sep 30, 2018 6:54, edited 1 time in total.
badidea
Posts: 1417
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: rotatable isometric image - still has a bug

Postby badidea » Sep 29, 2018 22:13

BasicCoder2 wrote:I will have to find a simple way to solve the frames per second issue for different compiles or computers.
It seems simpler with Javascript which I have been trying to learn where you simply set the milliseconds with

Code: Select all

setInterval(draw, 10);  // for 10 milliseconds

Do a search for dodicat's fps regulator. He makes useful stuff sometimes :-)

Some other thing. I would separate the the heavy calculations and sorting form the drawing itself. Now everything happens between screenlock/unlock. Although, currently a bit difficult because of 1 rot3D set.

Code: Select all

   screenlock
   calculate & sort
   draw tank 1
   calculate & sort
   draw tank 2
   screenunlock()

To (but not possible now):

Code: Select all

   calculate & sort
   calculate & sort
   screenlock
   draw tank 1
   draw tank 2
   screenunlock()
Last edited by badidea on Sep 29, 2018 22:19, edited 2 times in total.
dodicat
Posts: 5892
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: rotatable isometric image - still has a bug

Postby dodicat » Sep 29, 2018 22:16

My little regulator takes care of the framerate.

Code: Select all

   const ScrW = 1280
const ScrH = 480

const imgW = 100
const imgH = 100

'some useful defines
Const Pi = 4 * Atn(1)
Dim Shared As single TwoPi = 8 * Atn(1)
Dim Shared As single RtoD = 180 / Pi   ' radians * RtoD = degrees
Dim Shared As single DtoR = Pi / 180   ' degrees * DtoR = radians
dim shared as long fps
screenres ScrW,ScrH,32
color rgb(0,0,0),rgb(155,155,255):cls

'===========    make cube   ========================
dim shared as any ptr cube1
cube1 = imagecreate(32,33,rgb(255,0,255))
dim as integer x1,y1,x2,y2
for i as integer = 1 to 9
    read x1,y1,x2,y2
    line cube1,(x1,y1)-(x2,y2),rgb(0,0,0)
next i
paint cube1,(10,7),rgb(204,167,98),rgb(0,0,0)
paint cube1,(23,20),rgb(98,49,49),rgb(0,0,0)
paint cube1,(8,19),rgb(158,98,68),rgb(0,0,0)

data 16,0,31,8,  31,8,16,15,  15,16, 0,8,  0,8,15,0
data 31,24,16,32,  15,32,0,24,  31,8, 31,24,  15,16,15,32,  0,8,0,24
'======================================================

dim shared as any ptr ambulance
ambulance = imagecreate(61,47)
bload "ambulance4.bmp",ambulance

dim shared as any ptr top
top = imagecreate(110,31)
bload "top2.bmp",top

dim shared as any ptr image        'hold a image of rotated points
image = imagecreate(imgW,imgH)

type Point3D
    x as single
    y as single
    z as single
    c as ulong
end type

sub plot3D(x as single,y as single,z as single, c as ulong)
    'circle ( (x-y) + imgW/2, (x+y)/2 + z + imgH/2 ),1,c,,,,f
    pset image,( (x-y) + imgW/2, (x+y)/2 + z + imgH/2 ),c
end sub

'dodicat's fast qsort of points according to distance
Sub QsortZ(array() As Point3D,begin As Long,Finish As Ulong)
    Dim As Long i=begin,j=finish
    Dim As Point3D x =array(((I+J)\2))
    While I <= J
        While array(I).z > X .z:I+=1:Wend
        While array(J).z < X .z:J-=1:Wend
        If I<=J Then Swap array(I),array(J): I+=1:J-=1
    Wend
    If J >begin Then QsortZ(array(),begin,J)
    If I <Finish Then QsortZ(array(),I,Finish)
End Sub

Function Regulate(Byval MyFps As Long,Byref fps As Long) As Long
    Static As Double timervalue,lastsleeptime,t3,frames
    Var t=Timer
    frames+=1
    If (t-t3)>=1 Then t3=t:fps=frames:frames=0
    Var sleeptime=lastsleeptime+((1/myfps)-T+timervalue)*1000
    If sleeptime<1 Then sleeptime=1
    lastsleeptime=sleeptime
    timervalue=T
    Return sleeptime
End Function


type TANK
    as single  x          'x position of center of disc
    as single  y          'y position of center of disc
    as single  dx         'change in x position per cycle
    as single  dy         'change in y position per cycle
    as single  v          'speed restricted to -1.0 to +1.0
    as single  angle     'direction in degrees
end type

dim shared as integer MAX_DOTS
dim shared as integer TOT_DOTS
MAX_DOTS = 50000

dim shared as TANK t1,t2
t1.x = 0
t1.y = 0
t1.angle = 0


t2.x = 100
t2.y = 200
t2.angle = 0



'now dimension array of absolute position of points and array of rotated points
dim shared as Point3D abs3D(MAX_DOTS)  'absolute positions
dim shared as Point3D rot3D(MAX_DOTS)  'relative positions after any rotation

dim as ulong v,v2
dim as integer flag,x,y,z


' ============   create absolute point positions for ambulance  ==========
'edge data to draw back,top and bottom pixels of object
dim as integer edgeX(0 to 110),edgeY(0 to 110)
for i as integer = 0 to 110
    read edgeX(i),edgeY(i)
next i

for j as integer = 1 to 46
    flag = 0
    for i as integer = 0 to 60
        v = point(i,j,ambulance)
        if v <> rgb(255,0,255)  then
            abs3D(TOT_DOTS).x = i  - imgW/4
            abs3D(TOT_DOTS).y = 15
            abs3D(TOT_DOTS).z = j
            abs3D(TOT_DOTS).c = v
            if TOT_DOTS < MAX_DOTS then TOT_DOTS = TOT_DOTS + 1           
        end if
    next i
next j

for j as integer = 0 to 46
    for i as integer = 0 to 60
        v = point(i,j,ambulance)
        if v <> rgb(255,0,255) then
            abs3D(TOT_DOTS).x = i   - imgW/4
            abs3D(TOT_DOTS).y = -15
            abs3D(TOT_DOTS).z = j
            abs3D(TOT_DOTS).c = v
            if TOT_DOTS < MAX_DOTS then TOT_DOTS = TOT_DOTS + 1
        end if
    next i
next j

for i as integer = 0 to 109
    for y as integer = -15 to 15
        abs3D(TOT_DOTS).x = edgeX(i) -imgW/4
        abs3D(TOT_DOTS).y = y
        abs3D(TOT_DOTS).z = edgeY(i)
        abs3D(TOT_DOTS).c = point(i,y+15,top)
        if TOT_DOTS < MAX_DOTS then TOT_DOTS = TOT_DOTS + 1
    next y
next i

'=====================================================================

sub moveTank(t as TANK)
    t.dx = cos(t.angle*DtoR) * t.v
    t.dy = sin(t.angle*DtoR) * t.v
    t.x = t.x + t.dx
    t.y = t.y + t.dy
end sub

sub rotatePoints(tt as TANK)  'rotates points by tt.angle
   
    dim as single x,y,z,scale

    'rotate
    dim as single cosAngleX,sinAngleX,angleX
    dim as single cosAngleY,sinAngleY,angleY
    dim as single cosAngleZ,sinAngleZ,angleZ

   
    angleZ = tt.angle*DtoR    'angle to rotate points
    cosAngleZ = cos(angleZ)
    sinAngleZ = sin(angleZ)
    scale = 1/sqr(2)
   
    for i as integer = 0 to TOT_DOTS - 1  'rotate each point
        'rotate z axis
        x = abs3D(i).x
        y = abs3D(i).y
        z = abs3D(i).z
        rot3D(i).x = ((cosAngleZ * x) - (sinAngleZ * y))*scale
        rot3D(i).y = ((sinAngleZ * x) + (cosAngleZ * y))*scale
        rot3D(i).z = z*0.5
        rot3D(i).c = abs3D(i).c
    next i
   
    'sort by distance along z axis
    '***dodisort***
    Qsortz(rot3D(),Lbound(rot3D),TOT_DOTS - 1)

   
end sub

sub drawSprite(t as TANK)
   
    'clear image
    line image,(0,0)-(imgW-1,imgH-1),rgb(255,0,255),bf
    line image,(0,0)-(imgW-1,imgH-1),rgb(0,0,0),b  'show edge of image
   
    rotatePoints(t)  'rotate abs3D() points by t.angle to produce rot3D() points
   
    'draw rotated points onto image bitmap
    for i as integer = 0 to TOT_DOTS - 1
        plot3D(rot3D(i).x, rot3D(i).y, rot3D(i).z, rot3D(i).c)
    next i
   
    'cartesian to isometric coordinates of image
    dim as single tempX = (t.x - t.y) + 640 - imgW/2
    dim as single tempY = (t.x + t.y) / 2 + 30 - imgH/2
   
    'put rotated image on display
    put (tempX,tempY),image,trans
   
end sub

sub drawPoints()
    screenlock
    cls
    draw string (20,20),"FRAMERATE  " &fps
    'draw isometric cubes
    for y as integer = 0 to 24
        for x as integer = 0 to 24
            put ( (x*16-y*16) + SCRW/2 - 16, (x*16+y*16)/2 + 0 + 30 ),cube1,trans
        next x
    next y
   
    moveTank(t1)
    drawSprite(t1)  'draw rotated pixels onto image and place on screen
   
    moveTank(t2)
    drawSprite(t2)  'draw rotate pixels onto image and place on screen
   
    locate 2,2
    print t1.angle,t2.angle,TOT_DOTS
   
    screenunlock()
end sub

dim as single now1
now1 = timer


do
   
    if timer - now1 > 0.01 then
        now1 = timer
       
        drawPoints()
       
        '==================================================
        'cursor keys to control tank1
        t1.v = 0
   
        if multikey(&H50) then t1.v = -2 'REVERSE
        if multikey(&H48) then t1.v =  2 'FORWARD
       
        'rotate around z axis
        if multikey(&H4D) then
            t1.angle = t1.angle + 1
            if t1.angle > 360 then t1.angle = t1.angle - 360
        end if
        if multikey(&H4B) then
            t1.angle = t1.angle - 1
            if t1.angle < 0 then t1.angle = t1.angle + 360
        end if
       
        '==================================================
        'ASDW keys to control tank2
        t2.v = 0
       
        if multikey(&H11) then t2.v = -2 'REVERSE
        if multikey(&H1F) then t2.v =  2 'FORWARD
       
        'rotate around z axis
        if multikey(&H20) then
            t2.angle = t2.angle + 1
            if t2.angle > 360 then t2.angle = t2.angle - 360
        end if
        if multikey(&H1E) then
            t2.angle = t2.angle - 1
            if t2.angle < 0 then t2.angle = t2.angle + 360
        end if
       
    end if
   
    sleep regulate(60,fps) '<---------------  set fps here
   ' sleep 2
   
loop until multikey(&H01)


sleep

'coordinates of back, top and front of side edge of ambulance image to join using colors in top2 bitmap
data 0,30, 0,29, 0,28, 0,27, 1,27, 1,26, 1,25, 1,24, 1,23, 1,22, 1,21, 1,20, 1,19, 1,18, 1,19, 1,18, 1,17, 1,16
data 1,15, 1,14, 1,13, 1,12, 1,11, 1,10, 1,9, 1,8, 1,7, 1,6, 1,5, 1,4, 1,3, 1,2, 2,1, 3,0
data 4,0, 5,0, 6,0, 7,0, 8,0, 9,0, 10,0, 11,0, 12,0, 13,0, 14,0, 15,0, 16,0, 17,0, 18,0, 19,0, 20,0, 21,0
data 22,0, 23,0, 24,0, 25,0, 26,0, 27,0, 28,0, 29,0, 30,0, 31,0, 32,0, 33,0, 34,0, 35,0, 36,0, 37,0, 38,0, 39,0
data 40,0, 41,0, 42,0, 43,0, 44,0
data 44,1, 45,2, 45,3, 46,4, 46,5, 47,6, 47,7, 48,8, 48,9, 49,10, 49,11, 50,12, 51,13, 52,14, 53,14, 54,15, 55,15
data 56,16, 57,16, 58,17, 58,18, 58,19, 58,20, 58,21, 58,22, 58,23, 58,24, 58,25, 58,26, 58,27, 59,27, 60,27, 60,28, 60,29, 60,30
badidea
Posts: 1417
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: rotatable isometric image - still has a bug

Postby badidea » Sep 29, 2018 22:22

There it is. No search needed.

dodicat wrote:If you sort within the array range of i it seems OK
Qsortz(rot3D(),Lbound(rot3D),TOT_DOTS - 1)

Also a clear speed improvement now.
badidea
Posts: 1417
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: rotatable isometric image - still has a bug

Postby badidea » Sep 29, 2018 22:25

I ripped out all the shared variables (and the squared tiles accidentally):

Code: Select all

const ScrW = 1280
const ScrH = 480

const imgW = 100
const imgH = 100

'some useful defines
Const Pi = 4 * Atn(1)
const As single TwoPi = 8 * Atn(1)
const As single RtoD = 180 / Pi   ' radians * RtoD = degrees
const As single DtoR = Pi / 180   ' degrees * DtoR = radians

const as integer MAX_DOTS = 50000

'=============================== Types & subroutines ===========================

type Point3D
   x as single
   y as single
   z as single
   c as ulong
end type

sub plot3D(pImage as any ptr, x as single,y as single,z as single, c as ulong)
   'circle ( (x-y) + imgW/2, (x+y)/2 + z + imgH/2 ),1,c,,,,f
   pset pImage,( (x-y) + imgW/2, (x+y)/2 + z + imgH/2 ),c
end sub

'dodicat's fast qsort of points according to distance
Sub QsortZ(array() As Point3D,begin As Long,Finish As Ulong)
   Dim As Long i=begin,j=finish
   Dim As Point3D x =array(((I+J)\2))
   While I <= J
      While array(I).z > X .z:I+=1:Wend
      While array(J).z < X .z:J-=1:Wend
      If I<=J Then Swap array(I),array(J): I+=1:J-=1
   Wend
   If J >begin Then QsortZ(array(),begin,J)
   If I <Finish Then QsortZ(array(),I,Finish)
End Sub

type TANK
   as single  x          'x position of center of disc
   as single  y          'y position of center of disc
   as single  angle      'direction in degrees
   as single  dx         'change in x position per cycle
   as single  dy         'change in y position per cycle
   as single  v          'speed restricted to -1.0 to +1.0
end type

' ============   create absolute point positions for ambulance  ==========
'edge data to draw back,top and bottom pixels of object

sub read_calc_points(pAmbu as any ptr, pTop as any ptr, abs3D() as Point3D, byref numDots as integer)
   dim as ulong v,v2
   dim as integer x,y,z,flag
   dim as integer edgeX(0 to 110),edgeY(0 to 110)
   for i as integer = 0 to 110
      read edgeX(i),edgeY(i)
   next i
   for j as integer = 1 to 46
      flag = 0
      for i as integer = 0 to 60
         v = point(i,j,pAmbu)
         if v <> rgb(255,0,255)  then
            abs3D(numDots).x = i  - imgW/4
            abs3D(numDots).y = 15
            abs3D(numDots).z = j
            abs3D(numDots).c = v
            if numDots < MAX_DOTS then numDots += 1           
         end if
      next i
   next j
   for j as integer = 0 to 46
      for i as integer = 0 to 60
         v = point(i,j,pAmbu)
         if v <> rgb(255,0,255) then
            abs3D(numDots).x = i   - imgW/4
            abs3D(numDots).y = -15
            abs3D(numDots).z = j
            abs3D(numDots).c = v
            if numDots < MAX_DOTS then numDots += 1
         end if
      next i
   next j
   for i as integer = 0 to 109
      for y as integer = -15 to 15
         abs3D(numDots).x = edgeX(i) -imgW/4
         abs3D(numDots).y = y
         abs3D(numDots).z = edgeY(i)
         abs3D(numDots).c = point(i,y+15,pTop)
         if numDots < MAX_DOTS then numDots += 1
      next y
   next i
end sub

'=====================================================================

sub moveTank(t as TANK)
    t.dx = cos(t.angle*DtoR) * t.v
    t.dy = sin(t.angle*DtoR) * t.v
    t.x = t.x + t.dx
    t.y = t.y + t.dy
end sub

'rotates points by tt.angle
sub rotatePoints(tt as TANK, rot3D() as Point3D, abs3D() as Point3D, byref numDots as integer)
   dim as single x,y,z,scale
   'rotate
   dim as single cosAngleX,sinAngleX,angleX
   dim as single cosAngleY,sinAngleY,angleY
   dim as single cosAngleZ,sinAngleZ,angleZ
   'angle to rotate points
   angleZ = tt.angle*DtoR
   cosAngleZ = cos(angleZ)
   sinAngleZ = sin(angleZ)
   scale = 1/sqr(2)
   'rotate each point
   for i as integer = 0 to numDots - 1
      'rotate z axis
      x = abs3D(i).x
      y = abs3D(i).y
      z = abs3D(i).z
      rot3D(i).x = ((cosAngleZ * x) - (sinAngleZ * y))*scale
      rot3D(i).y = ((sinAngleZ * x) + (cosAngleZ * y))*scale
      rot3D(i).z = z * 0.5
      rot3D(i).c = abs3D(i).c
   next i
   'sort by distance along z axis
   '***dodisort***
   Qsortz(rot3D(), 0, numDots-1)
end sub

sub drawSprite(pImage as any ptr, t as TANK, rot3D() as Point3D, abs3D() as Point3D, numDots as integer)
   'clear image
   line pImage, (0,0)-(imgW-1,imgH-1),rgb(255,0,255),bf
   line pImage, (0,0)-(imgW-1,imgH-1),rgb(0,0,0),b  'show edge of image
   rotatePoints(t, rot3D(), abs3D(), numDots)  'rotate abs3D() points by t.angle to produce rot3D() points
   'draw rotated points onto image bitmap
   for i as integer = 0 to numDots - 1
      plot3D(pImage, rot3D(i).x, rot3D(i).y, rot3D(i).z, rot3D(i).c)
   next i
   'cartesian to isometric coordinates of image
   dim as single tempX = (t.x - t.y) + 640 - imgW/2
   dim as single tempY = (t.x + t.y) / 2 + 30 - imgH/2
   'put rotated image on display
   put (tempX,tempY), pImage, trans
end sub

sub drawPoints(pImage as any ptr, t1 as TANK, t2 as TANK, rot3D() as Point3D, abs3D() as Point3D, numDots as integer)
   screenlock
   cls
   moveTank(t1)
   drawSprite(pImage, t1, rot3D(), abs3D(), numDots)  'draw rotated pixels onto image and place on screen
   moveTank(t2)
   drawSprite(pImage, t2, rot3D(), abs3D(), numDots)  'draw rotate pixels onto image and place on screen
   locate 2,2
   print t1.angle, t2.angle, numDots
   screenunlock()
end sub

'================================== Main init ==================================

dim as integer totalDots

dim as TANK t1 = type (0, 0, 0) 'x, y, angle
dim as TANK t2 = type(100, 200, 0)

screenres ScrW,ScrH,32
color rgb(0,0,0),rgb(155,155,255):cls

dim as any ptr pAmbu = imagecreate(61,47)
bload "ambulance4.bmp", pAmbu

dim as any ptr pTop = imagecreate(110,31)
bload "top2.bmp", pTop

dim as any ptr pImage = imagecreate(imgW,imgH) 'image of rotated points

'now dimension array of absolute position of points and array of rotated points
dim shared as Point3D abs3D(MAX_DOTS)  'absolute positions
dim shared as Point3D rot3D(MAX_DOTS)  'relative positions after any rotation

read_calc_points(pAmbu, pTop, abs3D(), totalDots)

'================================== Main loop ==================================

dim as double now1 = timer

do
   if timer - now1 > 0.01 then
      now1 = timer
      drawPoints(pImage, t1, t2, rot3D(), abs3D(), totalDots)

      '==================================================
      'cursor keys to control tank1
      t1.v = 0
      if multikey(&H50) then t1.v = -2 'REVERSE
      if multikey(&H48) then t1.v =  2 'FORWARD
      'rotate around z axis
      if multikey(&H4D) then
         t1.angle = t1.angle + 1
         if t1.angle > 360 then t1.angle = t1.angle - 360
      end if
      if multikey(&H4B) then
         t1.angle = t1.angle - 1
         if t1.angle < 0 then t1.angle = t1.angle + 360
      end if
      
      '==================================================
      'ASDW keys to control tank2
      t2.v = 0
      if multikey(&H11) then t2.v = -2 'REVERSE
      if multikey(&H1F) then t2.v =  2 'FORWARD
      'rotate around z axis
      if multikey(&H20) then
         t2.angle = t2.angle + 1
         if t2.angle > 360 then t2.angle = t2.angle - 360
      end if
      if multikey(&H1E) then
         t2.angle = t2.angle - 1
         if t2.angle < 0 then t2.angle = t2.angle + 360
      end if
   end if
   sleep 2
loop until multikey(&H01)


sleep

'coordinates of back, top and front of side edge of ambulance image to join using colors in top2 bitmap
data 0,30, 0,29, 0,28, 0,27, 1,27, 1,26, 1,25, 1,24, 1,23, 1,22, 1,21, 1,20, 1,19, 1,18, 1,19, 1,18, 1,17, 1,16
data 1,15, 1,14, 1,13, 1,12, 1,11, 1,10, 1,9, 1,8, 1,7, 1,6, 1,5, 1,4, 1,3, 1,2, 2,1, 3,0
data 4,0, 5,0, 6,0, 7,0, 8,0, 9,0, 10,0, 11,0, 12,0, 13,0, 14,0, 15,0, 16,0, 17,0, 18,0, 19,0, 20,0, 21,0
data 22,0, 23,0, 24,0, 25,0, 26,0, 27,0, 28,0, 29,0, 30,0, 31,0, 32,0, 33,0, 34,0, 35,0, 36,0, 37,0, 38,0, 39,0
data 40,0, 41,0, 42,0, 43,0, 44,0
data 44,1, 45,2, 45,3, 46,4, 46,5, 47,6, 47,7, 48,8, 48,9, 49,10, 49,11, 50,12, 51,13, 52,14, 53,14, 54,15, 55,15
data 56,16, 57,16, 58,17, 58,18, 58,19, 58,20, 58,21, 58,22, 58,23, 58,24, 58,25, 58,26, 58,27, 59,27, 60,27, 60,28, 60,29, 60,30
BasicCoder2
Posts: 3394
Joined: Jan 01, 2009 7:03

Re: rotatable isometric image

Postby BasicCoder2 » Sep 29, 2018 23:48

dodicat wrote:My little regulator takes care of the framerate.

Thanks dodicat I will leave it in the evolving program.
Last edited by BasicCoder2 on Sep 30, 2018 6:54, edited 1 time in total.
BasicCoder2
Posts: 3394
Joined: Jan 01, 2009 7:03

Re: rotatable isometric image

Postby BasicCoder2 » Sep 29, 2018 23:56

badidea wrote:I ripped out all the shared variables (and the squared tiles accidentally):

Yep removing shared variables is a good thing.
There are many things "to do" next, but too numerous to list here, starting with a list of points for a tank object and probably having them in their own file so they don't have to be created from bitmaps. Then I can provide an isometric display of the tank game program.
BasicCoder2
Posts: 3394
Joined: Jan 01, 2009 7:03

Re: rotatable isometric image

Postby BasicCoder2 » Sep 30, 2018 7:05

Made some 3dPoint data of a simple tank for testing. The turret can be rotated independently to tank rotation.
Image

Return to “Game Dev”

Who is online

Users browsing this forum: No registered users and 2 guests