@Fluffy
I don't know if I code faster I've just been obsessed with this the past few days!
You are working on this too? Ah I may have tripped you up because I just re-structured a lot of it to try and get everything in smaller subroutines.
I've also added some material lighting effects to the bricks to make them look plastic,
big thanks to Latch for his guide on the material commands.
Rem * BRICK PARK
Rem * Created by Keanen Wendler-Shaw (26th April 2010)
rem * Version 0.1.3 by OBese87
rem ---
gosub _variables
gosub _init
gosub _loadmedia :`not including 3D stuff
rem /////////
rem Main
rem /////////
do
stop sound 1
gosub _main_menu
gosub _load3D
`loop sound 1 :`ambient sounds (birds)
rem if playing freeplay load our saved world
if freeplay=1 then loadbricks()
quit=0
rem //// Game Loop ////
repeat
gosub _data_update
gosub _input
`mode {
if build = 0
show object player : hide object brickghost
else
hide object player
rem cycle ghost brick color
if mzchange ! 0
inc bc, mzchange
if bc > maxcolors then bc = 0
if bc < 0 then bc = maxcolors
color object brickghost, color(bc)
endif
gosub _brickghost
rem place bricks
if buildok
show object brickghost
if action_build then placebrick(bx,by#,bz,bc) : play sound 2
else
hide object brickghost
if action_build then play sound 12
endif
endif
`}
gosub _process
gosub _animate_player
gosub _show_hud
rem update sky
position object 5,camera position x(),camera position y(),camera position z()
rem show player collision box indicator?
if shiftkey() then show object 4 else hide object 4
sync
until quit=1
if freeplay=1 then savebricks()
rem delete all objects
for i = 1 to 65535
if object exist(i) then delete object i
next i
delete matrix 1
loop
end
rem ////////////////
rem Subroutines
rem ////////////////
_animate_player:
if moving
rem rotate player to face camera direction
rotate object player, 0, cay#, 0
inc frame
if frame>16 then frame=1
select frame
case 1 : mesh=4 : endcase
case 3 : mesh=5 : endcase
case 5 : mesh=4 : endcase
case 7 : mesh=6 : endcase
case 9 : mesh=7 : endcase
case 11: mesh=8 : endcase
case 13: mesh=7 : endcase
case 15: mesh=6 : endcase
endselect
change mesh 1,0,mesh
else
frame=0
change mesh 1,0,2
endif
return
`//
_brickghost:
` bx = cx# + newxvalue(cx#,cay#,6)
` bz = cz# + newzvalue(cz#,cay#,6)
rem reset build permit
buildok = 1
rem roughly line up the ghost brick with the camera
position object brickghost, cx#, py# +4 , cz#
rem move ghost brick in front of camera
set object to camera orientation brickghost
move object brickghost,6
rotate object brickghost, 0,0,0 :`reset rotation
rem set maximum height difference player can build
yreach# = int(py#/1.2)*1.2+(pyreach*1.2)
rem convert ghost brick coords to integers
bx = object position x(brickghost)
bz = object position z(brickghost)
by# = yreach#
if bx<1 then bx=1
if bz<1 then bz=1
if bx>399 then bx=399
if bz>399 then bz=399
position object brickghost,bx,by#,bz
`Adjust the ghost brick's height until valid position found
rem (When brick placement becomes more sophisticated this will have to be redone.)
`{
rem don't detect collisions between ghost brick and player
set object collision off 1 : set object collision on 3
rem lower the brick until it hits another or ground
if object collision(3,0) = 0
rem downward looking build
rem move the brick down to find something to put it on
repeat
by# = by#-1.2
position object 3,bx,by#,bz
if by# < (py#-yreach#) then buildok=0 : exit
`the only way a downward-looking build can fail is if we are too far above other bricks or the ground.
until object collision(3,0)>0 or by#<0
by#=by#+1.2
position object brickghost,bx,by#,bz
else
rem here we can control attaching bricks to the underneath of others
rem and placing them on the ground below overhanging bricks. but to do
rem this we need to get the camera x angle involved.
rem move the brick down to find an open space
repeat
by# = by#-1.2
position object 3,bx,by#,bz
until object collision(3,0)=0 or by#<=1.2
position object brickghost,bx,by#,bz
`only allow to build if the space is free
if object collision(3,0)>0 then buildok=0
endif
`}
rem Turn normal collision back on
set object collision on 1 : set object collision off 3
return
`//
_data_update:
rem camera data
cx# = camera position x()
cy# = camera position y()
cz# = camera position z()
cax# = camera angle x()
cay# = camera angle y()
rem player data
px# = object position x(player)
py# = object position y(player)
pz# = object position z(player)
pay# = object angle y(player)
return
`//
_init:
set display mode sw,sh,32
disable escapekey
sync on
sync rate 40
autocam off
rem set font
set text font "Arial",1
set text to bold
set text size 20
return
`//
_input:
rem old user input
oldmz=mz
oldmc = mc
oldlmc = lmc
oldrmc = rmc
rem user input
up = keystate(forwardkey)
down = keystate(backkey)
left = keystate(leftkey)
right = keystate(rightkey)
mmx = mousemovex()
mmy = mousemovey()
mz = mousemovez()
mc = mouseclick() : lmc = (mc=1) : rmc = (mc=2)
rem analyse input
if rmc > oldrmc then build = 1-build :`switch build mode on new right-click.
action_build = lmc > oldlmc
mzchange = (mz-oldmz)/120 :`120 is one notch on the z wheel.
moving = up+down+left+right
return
`//
_load3D:
rem loading screen
cls
paste image 1,0,0
ink color(1),0
center text 400,580,"Loading..."
sync
wait 1000 :`remove from final
backdrop on
rem setup the lights
position light 0, 200, 500, 200
set directional light 0,0,-1,0
set ambient light 0
rem load in all of the player's poses
load mesh "Data\player\player.x",2
load mesh "Data\player\playerj.x",3
load mesh "Data\player\player1.x",4
load mesh "Data\player\player2.x",5
load mesh "Data\player\player3.x",6
load mesh "Data\player\player4.x",7
load mesh "Data\player\player5.x",8
rem load the player's texture
load image "Data\player\player.png",101
rem make the player from the first pose and texture
make object 1,2,101
scale object 1,75,75,75
position object 1,200,0,200
rem make player's collision box
make object collision box 1, -.8, 0, -.8, .8, 4.2, .8, 0
rem make a visible trace object for the collision box (testing purposes)
make object box 4, 1.6, 4.2, 1.6
ghost object on 4
hide object 4
set object collision off 4
rem make the ground
make matrix 1,400,400,1,1
load image "Data\grass.dds",102,2:prepare matrix texture 1,102,1,1:delete image 102
rem load brick mesh and make ghost brick
load mesh "Data\brick.x",1
make object 3,1,0 :`make ghost brick from mesh
make object collision box 3,-1,0,-1,1,1.2,1,0
set object collision off 3
ghost object on 3
color object 3, color(0)
set object emissive 3,-1
set object diffuse 3,-1
set object ambient 3,-1
rem load the skysphere
make object sphere 5,-5000:set object collision off 5
load image "Data\sky.png",5
texture object 5,5
set object emissive 5,16777215 :`make the sky glow
rem load in the trees
load object "Data\trees.x",6
load image "Data\trees.png",999
texture object 6,999
delete image 999
set object 6,1,0,1 :`make the trees have transparent backgrounds
set object collision off 6
return
`//
_loadmedia:
load music "Data\title.mp3",1
load image "Data\title.png",1
load image "Data\menu.png",104
load image "Data\help.png",2
load image "Data\stone.dds",3,1
load image "Data\sky2.png",4
load sound "Data\birds.wav",1
load sound "Data\click.wav",2
load sound "Data\jump.wav",3
load sound "Data\beep.wav",4
load sound "Data\1.wav",5
load sound "Data\2.wav",6
load sound "Data\3.wav",7
load sound "Data\4.wav",8
load sound "Data\volcano.wav",9
load sound "Data\5.wav",10
load sound "Data\whoops.wav",11
load sound "Data\ouch.wav",12
load sound "Data\6.wav",13
load sound "Data\whoops2.wav",14
load sound "Data\whoops3.wav",15
load sound "Data\whoops4.wav",16
load sound "Data\end.wav",17
return
`//
_main_menu:
backdrop off
show mouse
loop music 1
repeat
cls
rem title backdrop
paste image 1,0,0
rem record the mouse positions
mx=mousex() : my=mousey()
rem hover mouse over options
if my > (sh - 60)
select mx
case <(sw*.33) : option = 1 : endcase
case >(sw*.67) : option = 3 : endcase
case default : option = 2 : endcase
endselect
else
option = 0
endif
rem display the menu
for i = 1 to 3
if option=i then ink color(2),0 : j=3 else ink color(1),0 : j=0
center text (sw/4)*i,sh-20,opt$(i+j)
next i
sync
until mouseclick() and option>0
rem find which option was selected
select option
case 1 : freeplay=0 : endcase
case 2 : freeplay=1 : endcase
case 3 : end : endcase
endselect
hide mouse
stop music 1
return
`//
_process:
rem show help
oldF1 = newF1
newF1 = keystate(F1)
if newF1>oldF1 then showhelp = 1-showhelp
if showhelp then helpx=18
rem take screenshot
if keystate(F2) then gosub _screenshot
rem quit
if escapekey()
quit=1
endif
rem move player
`{
if up ! down
if up > down
px# = newxvalue(px#,cay#,spd#)
pz# = newzvalue(pz#,cay#,spd#)
else
px# = newxvalue(px#,cay#-180,spd#)
pz# = newzvalue(pz#,cay#-180,spd#)
endif
endif
if left ! right
if left > right
px# = newxvalue(px#,cay#-90,spd#)
pz# = newzvalue(pz#,cay#-90,spd#)
else
px# = newxvalue(px#,cay#+90,spd#)
pz# = newzvalue(pz#,cay#+90,spd#)
endif
endif
rem restrict player's movement to within 400 units
if px#<1 then px#=1
if pz#<1 then pz#=1
if px#>399 then px#=399
if pz#>399 then pz#=399
rem jumping
if spacekey() then inc py#, 2.4
`}
rem position player
`{
rem adjust player height
if py# <= 0 then py# = 0 else dec py#, 1.2
position object player,px#,py#,pz#
rem respond to any collisions caused
oc = object collision(player,0)
if oc>0
dec py#, get object collision y()*1.2
if object position y(oc) > py#
dec px#, get object collision x()
dec pz#, get object collision z()
endif
endif
rem reposition player
position object player, px#, py#, pz#
rem position player collision box indicator (hidden until shiftkey pressed)
position object 4, px#, py#+2.1, pz#
rotate object 4, 0, ay#, 0
`}
rem Camera
`{
rem change camera angles based on mouse movement
ax#=wrapvalue(ax#+mmy*mmdamp#)
ay#=wrapvalue(ay#+mmx*mmdamp#)
if ax#<270 and ax#>180 then ax#=270
if ax#>90 and ax#<180 then ax#=90
rotate camera ax#,ay#,0
rem put the camera at eye level
position camera px#, py#+4, pz#
rem switch 1st and 3rd person perspective
if build=0 then move camera -5
`}
return
`//
_screenshot:
rem get the date
date$=get date$()
date$=mid$(date$,7)+mid$(date$,8)+"-"+mid$(date$,1)+mid$(date$,2)+"-"+mid$(date$,4)+mid$(date$,5)
rem play the beep sound
play sound 4
rem hide the brick indicator and shadow
hide object 3
sync
rem save the image
get image 999,0,0,screen width(),screen height()
save image date$+"_"+str$(timer())+".bmp",999
delete image 999
sleep 500
rem unhide the brick indicator and shadow
show object 3
return
`//
_show_hud:
rem help message
if helpx<800
paste image 2,helpx,18,1
inc helpx,127
endif
rem HUD
paste image 104,0,0,1
return
`//
_variables:
rem constants
sw = 800 : sh = 600 :`screen dimensions.
spd# = .3 :`player move speed.
mmdamp#=.3 :`mouse movement damper.
pyreach = 4 :`number of vertical bricks the player can reach.
rem variables
helpx = 800
bc = 0 :`brickghost colour
rem Colours
maxcolors=9
dim color(maxcolors)
color(0)=rgb(255,0,0)
color(1)=rgb(255,128,0)
color(2)=rgb(255,255,0)
color(3)=rgb(0,255,0)
color(4)=rgb(0,255,255)
color(5)=rgb(0,0,255)
color(6)=rgb(128,0,255)
color(7)=rgb(255,255,255)
color(8)=rgb(128,128,128)
color(9)=rgb(16,16,16)
rem color of every brick stored
dim colorbrick(65535)
rem main menu options
dim opt$(6)
opt$(1) = "PLAY"
opt$(2) = "FREE BUILD"
opt$(3) = "QUIT"
opt$(4) = "P L A Y"
opt$(5) = "F R E E B U I L D"
opt$(6) = "Q U I T"
rem key labels
F1=59 : F2=60 : del=211
forwardkey = 17 :`W
backkey = 31 :`S
leftkey = 30 :`A
rightkey = 32 :`D
rem other labels
player = 1 : brickghost = 3
return
rem ///////////////
rem Functions
rem ///////////////
function grabval(main$,loc)
k$ = ""
j = 1+(4*loc)
for i = j to j+2
k$ = k$ + mid$(main$, i)
next i
k = val(k$)
endfunction k
`//
function loadbricks()
brickfile$="data\bricks.txt"
if file exist(brickfile$) = 0 then exitfunction -1
open to read 1,brickfile$
for x=9 to 65535
if object exist(x) then delete object x
next x
repeat
read string 1,s$
rem get brick data from file
bx = grabval(s$, 0)
by# = grabval(s$, 1)*1.2
bz = grabval(s$, 2)
bc = grabval(s$, 3)
rem make the brick
placebrick(bx,by#,bz,bc)
until file end(1)
close file 1
endfunction
`//
function placebrick(x,y#,z,c)
rem find a number for the brick
for obj=9 to 65535
if object exist(obj)=0 then exit
next obj
if obj=65536 then exitfunction -1 :`no available object number
rem make the brick
make object obj,1,0
make object collision box obj,-1,0,-1,1,1.2,1,0
colorbrick(obj) = c
color object obj,color(c)
set object diffuse obj,color(c)
set object ambient obj,rgb(64,64,64)
set object specular obj,-1,32
position object obj,x,y#,z
endfunction
`//
function savebricks()
brickfile$="data\bricks.txt"
if file exist(brickfile$) then delete file brickfile$
open to write 1,brickfile$
rem shove in some leading zeros for easier reading
dim zero$(2)
zero$(0) = ""
zero$(1) = "0"
zero$(2) = "00"
for i=9 to 65535
if object exist(i)
x$ = str$(int(object position x(i)))
x$ = zero$(3-len(x$)) + x$
y$ = str$(int(object position y(i)/1.2))
y$ = zero$(3-len(y$)) + y$
z$ = str$(int(object position z(i)))
z$ = zero$(3-len(z$)) + z$
c = colorbrick(i)
c$ = zero$(2) + str$(c)
write string 1, x$+","+y$+","+z$+","+c$+"#"
endif
next i
close file 1
undim zero$(2)
endfunction
`//
The change log is getting a bit long so I've made it a separate document.
Brick Park
Originally created by Keanen Wendler-Shaw (26th April 2010)
Newer versions by OBese87
------
== Change Log ==
Version 0.1.3 - 7th April 2012
NEW FEATURES
* Improved lighting effects.
* Major adjustments to the code structure: new subroutines and functions.
Some variable names changed for clarity.
BUGS
* Collision is inconsistent on half-brick steps.
* Camera can see through walls.
---
Version 0.1.2 - 6th April 2012
FIXES
* Building on your head.
NEW FEATURES
* Saving and loading now done in a 3-character format to simplify the process.
* Player re-sized to fit through 1x4x1 passages.
* Holding SHIFT shows the player collision box.
* While player is still, the camera can rotate around the player.
* Can now build on suspended half-bricks that stick out.
* There is now a limit to how high above the player he can reach to place bricks.
If there is no valid space to place a brick you will get a weird noise indicating
no block was placed.
---
It is coming along quite nicely, I feel like I have tamed the code now.
My next objective is to rework the brick placement so you place bricks where you are looking, so for example if you are under an outcrop you could look up and attach a brick to the underside of the outcrop, or look down and place it on the floor below. Placing bricks should still be limited to connecting them like Lego or placing on the ground, you shouldn't be able to place a brick on the side of another.
I need some help with a small bit of code. At the moment the brickghost (the object that indicates where your brick will be placed) is positioned by placing it in the player's position and then turning and moving it into view
rem roughly line up the ghost brick with the camera
position object brickghost, cx#, py# +4 , cz#
rem move ghost brick in front of camera
set object to camera orientation brickghost
move object brickghost,6
rotate object brickghost, 0,0,0 :`reset rotation
This is a bit sloppy and I wanted to replace it with this
bx = cx# + newxvalue(cx#,cay#,6)
bz = cz# + newzvalue(cz#,cay#,6)
but it doesn't seem to work and I don't understand why. I've tested the same code in a standalone program and it worked, so I'm confused as to what is going wrong. Any help is much appreciated.
That code is from the _brickghost subroutine if it helps.
WARNING: The above comment may contain sarcasm.