rotatable isometric image

Game development specific discussions.
Post Reply
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

rotatable isometric image

Post by BasicCoder2 »

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: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: rotatable isometric image - still has a bug

Post by badidea »

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: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: rotatable isometric image - still has a bug

Post by dodicat »

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

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

Re: rotatable isometric image

Post by BasicCoder2 »

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: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: rotatable isometric image - still has a bug

Post by badidea »

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: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: rotatable isometric image - still has a bug

Post by dodicat »

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: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: rotatable isometric image - still has a bug

Post by badidea »

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: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: rotatable isometric image - still has a bug

Post by badidea »

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: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: rotatable isometric image

Post by BasicCoder2 »

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: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: rotatable isometric image

Post by BasicCoder2 »

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: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: rotatable isometric image

Post by BasicCoder2 »

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