Another weekend has passed and I haven't had time to tidy this again... SO, here is the messy version of SMASH-IT!
No media in this version, so you can just copy and paste into a new project. I'll try to make it pretty during the week. Probably requires a bunch of tweaks too... this was my first attempt at a 3D game!
Code is here:
SetWindowSize( 1000, 500, 0 ) : SetVirtualResolution( 300, 120 )
SetOrientationAllowed( 1, 1, 1, 1 )
SetSyncRate( 60, 0 )
UseNewDefaultFonts( 1 ) // since version 2.0.20 we can use nicer default fonts
// We'll be using Bullet Physics for this example, so first we must initiate the physics engine:
Create3DPhysicsWorld()
Set3DPhysicsGravity(0,-1.8,0)
// Create a little atmosphere
SetFogMode(1)
SetFogColor(220,220,250)
SetFogRange(250,600)
SetClearColor(230,230,250)
SetCameraRange(1,10,600)
//turn off scissor so there's no black bars
SetScissor(0,0,0,0)
bullets as integer[]
cones as integer[]
blocks as integer[]
vc3 = CreateVector3()
//reserve objects 500 to 560 for our 3d blocks that will explode when we blow up a cone
// Improvement: Create a cone out of pre-broken chunks that could be used instead of blocks to make it look like the cone itself breaks apart.
// Further future improvement: Chop the cone object into pieces with CSG commands (when available) and use those as our 3d particles.
global particles as integer[60]
for t = 0 to 60
particles[t] = t+500
next t
global particlecounter as integer
// We'll be using good old PRINT in this example, so let's set the size and colour here
// Improvement: Replace the PRINT statements with funky text, positioned more appropriately in the game
SetPrintSize(16)
SetPrintColor(0,0,0)
do
SetRandomSeed(1) // This will make sure the level is always the same - Use SetRandomSeed(timer()) if you want different levels each time
// Set a variable to track which level the player is on
level = 0
// Display a gameover screen
while GetPointerReleased() =0
print("GAME OVER - Score: "+str(score))
print("click to play")
sync()
endwhile
//Initialise some variables used in our game
speed#=1.0
score = 0
ShotsLeft = 5
gameover=0
while gameover = 0
inc level,1
particlecounter=0 : speed# = speed# + 0.4
Delete3DPhysicsWorld() : Create3DPhysicsWorld() : Set3DPhysicsGravity(0,-1.8,0)
DeleteAllObjects()
// Now we will build a floor...
planefloor = CreateObjectPlane(2000,15000)
SetObjectColor(planefloor,50,70,150,255)
RotateObjectLocalX(planefloor,90)
// ... and make it solid so it reacts to physics objects...
Create3DPhysicsStaticBody(planefloor)
SetObjectShapeStaticPolygon(planefloor)
SetObject3DPhysicsGroupAndMask( planefloor, 2, 1 )
// Put the camera in our start position
SetCameraPosition(1,200,30,-600)
SetCameraRotation(1,0,0,0)
// Position some blocks and cones to represent our levels...
// This is a loop
for x = 1 to 8
// This is a nested loop
for z = 1 to 100
if random(1,5) = 5 // We don't want a block to appear at every position on our landscape, so we'll do an average of 1 out of 5... Try changing this if you want more (or less) blocks.
towerheight = random(5,25) : b=CreateObjectBox(10,towerheight,10)
SetObjectColor(b,random(200,255),random(200,255),random(200,255),255)
SetObjectPosition(b,(x+5)*20,towerheight/2,z*20)
Create3DPhysicsStaticBody( b )
SetObjectShapeBox(b)
SetObjectVisible(b,0) // Hide all our blocks for now...
blocks.insert(b) // We're using an array to keep track of our block IDs
if random(1,7) = 7 and x > 2 and x < 7 // We want roughly 1 out of every 7 blocks to have a cone on it as a target for the player to hit, and don't want any targets to appear on the outside edges.
// create the cone with a bit of variation on the height
coneheight = random(20,45) : b=CreateObjectCone(coneheight,15,4)
// Make the target dark blue
SetObjectColor(b,55,55,255,255)
// Position the cone so it appears on top of a block
SetObjectPosition(b,(x+5)*20,towerheight+(coneheight/2),z*20)
// Create a physics body for our target so we have something for the player's bullets to collide with
Create3DPhysicsStaticBody( b )
SetObjectShapeCone(b,1)
//SetObject3DPhysicsGroupAndMask( b, 1, 2 )
// We're using an array to keep track of our cone IDs.
cones.insert(b)
endif
endif
next z
next x
// We will determine whether the player has reached the end of a level of the camera z position goes over 2100
while GetCameraZ(1)<2100 and gameover=0
// Move the camera forward by the speed speed# (try changing the value of speed# to see what happens!)
MoveCameraLocalZ(1,speed#)
// only make the blocks and cones visible is they are close enough to the camera to see, otherwise we are wasting valuable rendering power.
for t = 0 to blocks.length
if (getobjectz(blocks[t]) - getcameraz(1)) < 650
SetObjectVisible(blocks[t],1)
endif
next t
// We want to be able to fire bullets so...
if GetPointerPressed() and ShotsLeft>0
// The player has fired a bullet, so we must reduced the number of shots left which is stored in the ShotsLeft variable
dec ShotsLeft,1
bullet = CreateObjectSphere(3,6,6)
SetObjectPosition(bullet,getcamerax(1),getcameray(1),getcameraz(1))
Create3DPhysicsDynamicBody( bullet )
SetObjectShapeSphere(bullet)
//SetObject3DPhysicsGroupAndMask( bullet, 1, 2 )
// Not a particularly accurate way to aim the bullets, but does the job for this example (try changing the last value to make the bullets faster)
SetObject3DPhysicsLinearVelocity(bullet,(GetPointerX()-150),60-getpointery(),300,400)
bullets.insert(bullet)
endif
// Check for collisions
hitflag=0
for t = 0 to bullets.length
for ct = 0 to cones.length
// This is the only command I could find that allows you to check for a collision between two objects... ???
hitobj = GetObjects3DPhysicsContactPositionVector(bullets[t],cones[ct],vc3)
if hitobj <> 0
doparticlebomb(cones[ct],getobjectx(cones[ct]),getobjecty(cones[ct]),getobjectz(cones[ct]))
Delete3DPhysicsBody(cones[ct])
DeleteObject(cones[ct])
cones.remove(ct)
inc score,1
inc ShotsLeft,1 // We get a bullet back if we hit a target
endif
next
next
// Here we check whether it is game over. Game Over is when the player has run out of bullets and misses a target
if ShotsLeft < 1
// loop through all the cones to see if the player has missed any
for cl = 0 to cones.length
if getobjectz(cones[cl]) < getcameraz(1)
gameover=1
endif
next cl
endif
// Get the physics engine to do it's thing
Step3DPhysicsWorld()
//display some metrics
Print("level: "+str(level))
Print("score: "+str(score))
Print("Shots Left: "+str(ShotsLeft))
//remove stuff that's behind us
for t = 1 to blocks.length
if getobjectz(blocks[t]) < getcameraz(1)
Delete3DPhysicsBody(blocks[t])
DeleteObject(blocks[t])
blocks.remove(t)
endif
next t
for t = 0 to cones.length
if getobjectz(cones[t]) < getcameraz(1)
Delete3DPhysicsBody(blocks[t])
DeleteObject(blocks[t])
cones.remove(t)
endif
next t
// and SYNC
sync()
endwhile
endwhile
loop
function doparticlebomb(objid as integer, x as integer, y as integer, z as integer)
for t = 1 to 10
particlecounter = particlecounter + 1
if particlecounter > 60 then particlecounter = 0 //Limit number of particles to 60 for performance
if GetObjectExists(particles[particlecounter]) = 0
CreateObjectBox(particles[particlecounter],random(1,3),random(1,3),random(1,3))
endif
SetObjectPosition(particles[particlecounter],getobjectx(objid)+random2(-8,8),getobjecty(objid)+random2(-10,10),getobjectz(objid)+random2(-8,8))
Create3DPhysicsDynamicBody(particles[particlecounter])
SetObjectShapeBox(particles[particlecounter])
//SetObject3DPhysicsGroupAndMask( particles[particlecounter], 2, 1 )
SetObjectColor(particles[particlecounter],50,80,250,255)
// SetObject3DPhysicsLinearVelocity(particle,90+random2(-10,10),random2(-10,10),random2(-10,10)+90,random(150,250))
SetObject3DPhysicsLinearVelocity(particles[particlecounter],0+random2(-20,20),90+random2(-20,20),90+random2(-20,20),random(40,130))
SetObject3DPhysicsAngularVelocity(particles[particlecounter],random2(-100,100),random2(-100,100),random2(-100,100),random(5,60))
next t
endfunction