http://www.craftanimations.com/ Though its quite expensive to ‘play around with’ just for laughs… Works directly in the viewport drive around over obsticals, skid, burnout w/e you like :).
Thank you so much! I’m sure this will provide me with 24 hours of very exciting entertainment!
Too bad there way to expensive!
But 24 hours will do me
Today is the deadline for the challenge!
I will be posting my efforts this evening.
Incidentally, TzMtN has just posted a tic tac toe game in the main maxscript forum here:
http://forums.cgsociety.org/showthread.php?f=98&t=640853
erilaz – Thanks for the tip
I usually love mxs challenges, but never maneged to participate in one.
This time I was unaware of the challenge completely until you tipped me.
I hope I haven't disqualified myself from participating so I'll post my code
and make it official:
try destroyDialog TTTRollout catch ()
rollout TTTRollout "TTT"
(
-- Local Variable Declerations
------------------------------------------
local dim = 120
local valArr
local testValArr
local sequence
local tickTest = false
local movesHistory
-- User Interface
------------------------------------------
dropDownList ddlLevel "Level:" items:#("Beginner","Veteran","Expert","Imposible")
button bnNext "Next Turn" width:dim align:#center enabled:false
button bn02 "" width:(dim/3) height:(dim/3) align:#center
button bn01 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x - dim/3,bn02.pos.y]
button bn03 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x + dim/3,bn02.pos.y]
button bn04 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x - dim/3,bn02.pos.y + dim/3]
button bn05 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x,bn02.pos.y + dim/3]
button bn06 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x + dim/3,bn02.pos.y + dim/3]
button bn07 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x - dim/3,bn02.pos.y + dim*2/3]
button bn08 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x,bn02.pos.y + dim*2/3]
button bn09 "" width:(dim/3) height:(dim/3) pos:[bn02.pos.x + dim/3,bn02.pos.y + dim*2/3]
button bnUndo "Undo (0)" width:dim align:#center
button bnRestart "Restart" width:dim align:#center
label lbWins " Wins:" align:#left
label lbLosts "Losts: " align:#right offset:[0,-18]
spinner spWins "" fieldWidth:40 align:#left type:#integer enabled:false
spinner spLosts "" fieldWidth:40 align:#right type:#integer offset:[0,-22] enabled:false
timer tmEnd interval:100 active:false
-- Functions
------------------------------------------
fn updateUI =
(
fn getLabel lin row =
(
local label = ""
if valArr[lin][row] > 0 then label = "X"
if valArr[lin][row] < 0 then label = "O"
label
)
bn01.enabled = (bn01.caption = getLabel 1 1).count == 0
bn02.enabled = (bn02.caption = getLabel 1 2).count == 0
bn03.enabled = (bn03.caption = getLabel 1 3).count == 0
bn04.enabled = (bn04.caption = getLabel 2 1).count == 0
bn05.enabled = (bn05.caption = getLabel 2 2).count == 0
bn06.enabled = (bn06.caption = getLabel 2 3).count == 0
bn07.enabled = (bn07.caption = getLabel 3 1).count == 0
bn08.enabled = (bn08.caption = getLabel 3 2).count == 0
bn09.enabled = (bn09.caption = getLabel 3 3).count == 0
if bnRestart.caption != "Restart" then bnNext.enabled = false
bnUndo.enabled = movesHistory.count > 1
bnUndo.caption = "Undo (" + (movesHistory.count - 1) as string + ")"
)
fn appendMovesHistory =
(
append movesHistory #()
for lin = 1 to 3 do (
append movesHistory[movesHistory.count] #()
for row = 1 to 3 do (
append movesHistory[movesHistory.count][lin] valArr[lin][row]
)
)
)
fn testGameEnd vArr readOnly:false =
(
local test = 0
sequence = #()
for a = 1 to 3 do (
if vArr[a][1] == vArr[a][2] and vArr[a][1] == vArr[a][3] then
(
if vArr[a][1] > 0 then test = 1
if vArr[a][1] < 0 then test = -1
if vArr[a][1] != 0 then sequence = #([a,1],[a,2],[a,3])
)
if vArr[1][a] == vArr[2][a] and vArr[1][a] == vArr[3][a] then
(
if vArr[1][a] > 0 then test = 1
if vArr[1][a] < 0 then test = -1
if vArr[1][a] != 0 then sequence = #([1,a],[2,a],[3,a])
)
) --end a loop
if vArr[1][1] == vArr[2][2] and vArr[1][1] == vArr[3][3] then
(
if vArr[1][1] > 0 then test = 1
if vArr[1][1] < 0 then test = -1
if vArr[1][1] != 0 then sequence = #([1,1],[2,2],[3,3])
)
if vArr[1][3] == vArr[2][2] and vArr[1][3] == vArr[3][1] then
(
if vArr[1][3] > 0 then test = 1
if vArr[1][3] < 0 then test = -1
if vArr[1][3] != 0 then sequence = #([1,3],[2,2],[3,1])
)
if test == 0 then (
for lin = 1 to 3 do (
for row = 1 to 3 do (
if test == 0 and vArr[lin][row] == 0 then test = 2
)
)
)
if not readOnly then (
case of
(
(test == 0):
(
bnRestart.caption = "Tie!"
movesHistory = #()
)
(test == 1):
(
bnRestart.caption = "You Win!"
spWins.value += 1
movesHistory = #()
)
(test == -1):
(
bnRestart.caption = "You Lose!"
spLosts.value += 1
movesHistory = #()
)
defalut:
(
bnRestart.caption = "Restart"
)
)
if sequence.count == 3 then tmEnd.active = true
)
test
)
fn setMatrix lin row val force:false =
(
if (not bnNext.enabled or force) and bnRestart.caption == "Restart" then (
valArr[lin][row] = val
bnNext.enabled = not bnNext.enabled
testGameEnd valArr
appendMovesHistory()
updateUI()
)
)
fn calculateMove =
(
local posibleMoves = #()
local corners = #([1,1],[1,3],[3,1],[3,3])
local sides = #([1,2],[2,1],[2,3],[3,2])
-- [0] Error posibility test:
-------------------------------
local errorTest = case ddlLevel.selection of (
1: true
2: random 1 3 == 2
3: random 1 9 == 5
4: false
)
if errorTest then (
for lin = 1 to 3 do (
for row = 1 to 3 do (
if valArr[lin][row] == 0 then (
append posibleMoves [lin,row]
format "Error
"
)
)
)
)
-- [1] Win posibility test:
--------------------------------
if posibleMoves.count == 0 then (
for lin = 1 to 3 do (
for row = 1 to 3 do (
if valArr[lin][row] == 0 then (
valArr[lin][row] = -1
if testGameEnd valArr readOnly:true == -1 then (
append posibleMoves [lin,row]
format "Win
"
)
valArr[lin][row] = 0
)
)
)
)
-- [2] Block posibility test:
---------------------------------
if posibleMoves.count == 0 then (
for lin = 1 to 3 do (
for row = 1 to 3 do (
if valArr[lin][row] == 0 then (
valArr[lin][row] = 1
if testGameEnd valArr readOnly:true == 1 then (
append posibleMoves [lin,row]
format "Block
"
)
valArr[lin][row] = 0
)
)
)
)
-- [3] Sandwich posibility test:
-----------------------------------
if posibleMoves.count == 0 then (
if valArr[2][2] == -1 then (
for c = 1 to corners.count where valArr[corners[c].x][corners[c].y] == 1 do (
if valArr[corners[5 - c].x][corners[5 - c].y] == 1 do (
for s in sides where valArr[s.x][s.y] == 0 do (
append posibleMoves s
format "Sandwich
"
)
)
)
)
)
-- [4] Fork posibility test:
--------------------------------
if posibleMoves.count == 0 then (
for lin = 1 to 3 do (
for row = 1 to 3 do (
if valArr[lin][row] == 0 then (
valArr[lin][row] = -1
local winCount = 0
for lin2 = 1 to 3 do (
for row2 = 1 to 3 do (
if valArr[lin2][row2] == 0 then (
valArr[lin2][row2] = -1
if testGameEnd valArr readOnly:true == -1 then (
winCount += 1
)
valArr[lin2][row2] = 0
)
)
)
if winCount > 1 then (
append posibleMoves [lin,row]
format "Fork posibility
"
)
valArr[lin][row] = 0
)
)
)
)
-- [5] Block Fork posibility test:
----------------------------------------
if posibleMoves.count == 0 then (
for lin = 1 to 3 do (
for row = 1 to 3 do (
if valArr[lin][row] == 0 then (
valArr[lin][row] = 1
local winCount = 0
for lin2 = 1 to 3 do (
for row2 = 1 to 3 do (
if valArr[lin2][row2] == 0 then (
valArr[lin2][row2] = 1
if testGameEnd valArr readOnly:true == 1 then (
winCount += 1
)
valArr[lin2][row2] = 0
)
)
)
if winCount > 1 then (
append posibleMoves [lin,row]
format "Block Fork posibility
"
)
valArr[lin][row] = 0
)
)
)
)
-- [6] Empty Centre posibility test:
--------------------------------------------
if posibleMoves.count == 0 then (
if valArr[2][2] == 0 then (
append posibleMoves [2,2]
format "Empty Centre
"
)
)
-- [7] Opposite Corner posibility test:
------------------------------------------------
if posibleMoves.count == 0 then (
for a = 1 to sides.count do (
if valArr[sides[a].x][sides[a].y] == 1 then (
b = 5 - a
if valArr[sides[b].x][sides[b].y] == 0 then (
append posibleMoves sides[b]
format "Opposite Corner
"
)
)
)
)
-- [8] Empty Corner posibility test:
-----------------------------------------
if posibleMoves.count == 0 then (
for i in corners do (
if valArr[i.x][i.y] == 0 then (
append posibleMoves i
format "Empty Corner
"
)
)
)
-- [9] Empty Side posibility test:
--------------------------------------------
if posibleMoves.count == 0 then (
for i in sides do (
if valArr[i.x][i.y] == 0 then (
append posibleMoves i
format "Empty Side
"
)
)
)
-- Make a move:
---------------------
local newMove = posibleMoves[random 1 posibleMoves.count]
setMatrix newMove.x newMove.y -1 force:true
)
fn nextTurn =
(
calculateMove()
updateUI()
)
fn restartGame =
(
tmEnd.active = true
valArr = #(#(0,0,0),#(0,0,0),#(0,0,0))
movesHistory = #(#(#(0,0,0),#(0,0,0),#(0,0,0)))
bnRestart.caption = "Restart"
bnNext.enabled = false
updateUI()
)
fn showWinner =
(
if bnRestart.caption == "You Win!" or bnRestart.caption == "You Lose!" then (
local char = if bnRestart.caption == "You Win!" then "X" else "O"
for i in sequence do (
if i == [1,1] then bn01.caption = if tickTest then char else ""
if i == [1,2] then bn02.caption = if tickTest then char else ""
if i == [1,3] then bn03.caption = if tickTest then char else ""
if i == [2,1] then bn04.caption = if tickTest then char else ""
if i == [2,2] then bn05.caption = if tickTest then char else ""
if i == [2,3] then bn06.caption = if tickTest then char else ""
if i == [3,1] then bn07.caption = if tickTest then char else ""
if i == [3,2] then bn08.caption = if tickTest then char else ""
if i == [3,3] then bn09.caption = if tickTest then char else ""
)
tickTest = not tickTest
)
)
fn UndoMove =
(
deleteItem movesHistory movesHistory.count
valArr = movesHistory[movesHistory.count]
bnNext.enabled = not bnNext.enabled
updateUI()
)
fn openDialog =
(
createDialog TTTRollout width:(dim + 25)
)
fn init =
(
restartGame()
)
fn done =
(
-- cleanup code
gc light:true
)
-- Event Handlers
------------------------------------------
on bn01 pressed do setMatrix 1 1 1
on bn02 pressed do setMatrix 1 2 1
on bn03 pressed do setMatrix 1 3 1
on bn04 pressed do setMatrix 2 1 1
on bn05 pressed do setMatrix 2 2 1
on bn06 pressed do setMatrix 2 3 1
on bn07 pressed do setMatrix 3 1 1
on bn08 pressed do setMatrix 3 2 1
on bn09 pressed do setMatrix 3 3 1
on bnRestart pressed do restartGame()
on bnUndo pressed do UndoMove()
on bnNext pressed do nextTurn()
on tmEnd tick do showWinner()
on TTTRollout open do init()
on TTTRollout close do done()
) -- end of rollout
TTTRollout.openDialog()
By the way, this code has a new undo feature in it!
Written in Max 2008 by the way.
Here are my references:
[ http://en.wikipedia.org/wiki/Tic-tac-toe ]( http://en.wikipedia.org/wiki/Tic-tac-toe)
[ http://www.wikihow.com/Win-at-Tic-Tac-Toe ]( http://www.wikihow.com/Win-at-Tic-Tac-Toe)
Thanks to PEN and ZeBoxx2 for their help!
Cheers, Matan.
Not a work of genius, this is a simple replication of the classic puzzle toy. The fun stuff was the dynamic parenting, which is still a bit funny. Uncomment the line near the bottom for 1-click 90 degree rotation.
-------------------------------------------------------------
-- SCRIPT: "Cube Puzzle"
-- VERSION 1.0a
-- AUTHOR: Martin Brennand
-- DATE: 28/05/2008
-- NOTES: Simple Rubiks cube. Not quite right yet. :)
--
--FAULTS: The event trigger causes some irregularity in
-- the parenting of the cubes, so rotation can be
-- skewed.
-------------------------------------------------------------
(
tempObj = 0
cubeArray = 0
spinners = 0
rot = eulerangles 0 0 0
fn createCube mat=
(
local idx = 1
local cubeArray = #()
startPos = [-20,-20,-20]
for l = 1 to 3 do
(
for d = 1 to 3 do
(
for w = 1 to 3 do
(
cubeName = "cube_"+(idx as string)
cubeArray[idx] = box name:cubeName width:10 height:10 length:10
centerPivot cubeArray[idx]
cubeArray[idx].pos = startPos + [l*10,d*10,w*10]
addModifier (cubeArray[idx]) (Edit_Poly())
cubeArray[idx].isFrozen = true
cubeArray[idx].showFrozenInGray = false
idx +=1
)
)
)
selection = cubeArray
selection.Material = mat
return cubeArray
)
fn createMaterials =
(
local materialArray = #()
local mColours = #(red,green,blue,yellow,orange,black)
for i = 1 to 6 do
(
materialArray[i] = standardMaterial diffuse:mColours[i]
)
multiMat = multiMaterial numsubs:6
multiMat.materialList = materialArray
return multiMat
)
fn createSpinners cubes=
(
local spinnerArray = #()
for i = 1 to 3 do
(
spinnerArray[i] = circle radius: 25
if ( mod i 3 )== 0 then
(
spinnerArray[i].pos += [0,0,10]
)
if ( mod i 2 )== 0 then
(
spinnerArray[i].pos += [0,0,-10]
)
)
for i = 4 to 6 do
(
spinnerArray[i] = circle radius: 25
rot = (eulerangles 0 90 0)
spinnerArray[i].rotation = rot
if ( mod i 3 )== 0 then
(
spinnerArray[i].pos += [10,0,0]
)
if ( mod i 4 )== 0 then
(
spinnerArray[i].pos += [-10,0,0]
)
)
for i = 7 to 9 do
(
spinnerArray[i] = circle radius: 25
rot = (eulerangles 90 0 0)
spinnerArray[i].rotation = rot
if ( mod i 3 )== 0 then
(
spinnerArray[i].pos += [0,10,0]
)
if ( mod i 2 )== 0 then
(
spinnerArray[i].pos += [0,-10,0]
)
)
return spinnerArray
)
fn randomiseSpinners spinnerArr =
(
numSpins = random 50 100
spinnerCount = spinnerArr.count
for i = 1 to numSpins do
(
select spinnerArr[(random 1 spinnerCount)]
in coordsys local rotate selection (angleaxis 90 [0, 0 ,1])
)
)
rollout cubePuzzle "cubey puzzley" width:79 height:73
(
button quitBtn "Quit" pos:[23,44] width:35 height:21
button spinButton "Shuffle" pos:[18,13] width:49 height:21
on cubePuzzle open do
(
print "Dialog Init"
)
on cubePuzzle close do
(
deleteAllChangeHandlers id:#spinnerRotate
delete cubeArray
delete spinners
print "Dialog Closed"
)
on quitBtn pressed do
(
DestroyDialog cubePuzzle
)
on spinButton pressed do
(
randomiseSpinners(spinners)
)
)
--------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------
--create the objects
multiMat = createMaterials()
cubeArray = createCube(multiMat)
spinners = createSpinners(cubeArray)
--start the game cycle
createDialog cubePuzzle
when select spinners change id:#spinnerRotate obj do
(
if obj != tempObj then --don't parent more than once per selection!
(
for item in obj.children do (deleteItem obj.children item) --clear the children from the spinner
spinnerTransform = obj.transform.position
rotationGroup = #()
for i = 1 to cubeArray.count do
(
if (intersects cubeArray[i] obj) then
(
append rotationGroup cubeArray[i]
)
)
rotationGroup.parent = obj
tempObj = obj
)
--in coordsys local rotate selection (angleaxis 90 [0, 0 ,1]) --one-click rotation
)
)
Hey Erilaz,
I couldn’t get your game to work!
-- Error occurred in <handler>()
-- Frame:
-- spinnerTransform: [0,10,0]
-- Obj: $Circle09
-- rotationGroup: #($cube_7, $cube_8, $cube_9, $cube_16, $cube_17, $cube_18, $cube_25, $cube_26, $cube_27)
>> MAXScript Change Handler Exception: -- No ""rotate"" function for undefined <<
??
Hmm… odd. What version of max are you using? I’ve been coding and testing in 2009. I assume this happens when you click shuffle, or does it happen immediately?
Great work on the snake game, although i’m finding it a bit hard to control!
OK, Here’s MaxSnake. Lots of potential here for a killer game I think. I especially enjoyed:
[ul]
[li]The mouse interaction[/li][li]Having the segments follow in a chain-like fashion[/li][li]Having functions called “KillPill” and “EatPill” heh heh[/li][/ul]
-- Script: MAXSnake!
-- Author: Dave Stewart
-- Release: 0.5
-- MaxVersion: Tested on 8, will probably work on lower versions quite happily.
-- Date: June 6th 2007
-- Description: Use your mouse to play a variation on the classic Snake game!
-- Instructions:The aim of teh game is to survive as long as possible, or shorten your
-- body by eating power pills. If you accidentally bump a pill without
-- eating it your body gets longer. If you ru over your own body, your
-- body gets longer. Have fun!
-- To do: Scoring, finish bumpy board (and animate it) probably tinker with gameplay, finish the bumpy course.
clearListener()
try (destroydialog roMAXSnake); catch(err)
rollout roMAXSnake "MAXSnake!" width:160 height:40
(
local arrSegs = #()
local arrPills = #()
local arrObjs = #()
local segCount = 15
local timerInterval = 10
local mouseObj
local createPills, eatPill, cleanup
local isColliding = false
local counter = 0
local counterMax = 20
local boardSize = 3000
local boardIsBumpy = false
local vptLayout = viewport.getLayout()
Timer tmr1 "Timer" pos:[8,40] width:24 height:24 interval:100
checkButton ckbTimer "Active" pos:[8,8] width:72 height:24 checked:true
button btnRestart "Restart" pos:[80,8] width:74 height:24
fn planeLineIntersect planePoint planeNormal linePoint lineVector =
(
local lineVector = normalize lineVector
local d1 = dot (planePoint - linePoint) planeNormal
local d2 = dot lineVector planeNormal
if abs d2 < 0.0000000754 then
(
if abs d1 > 0.0000000754 then 0 else -1
)
else(
linePoint + ( (d1/d2) * lineVector )
)
)
fn moveToSurface src trg =
(
r1 = ray (src.pos + [0,0,10000]) [0,0,-1]
r2 = intersectRay trg r1
z = if r2 == undefined then 0 else r2.pos.z
src.pos.z = z
)
fn getMousePos =
(
local p = mouse.pos
local r = mapScreenToWorldRay p
local p3 = planeLineIntersect [0,0,0] [0,0,1] r.pos r.dir
p3
)
function addSegment trgObj: col: =
(
-- create
local obj = box()
if col == unsupplied do col = red
obj.wirecolor = col
obj.pivot = obj.center
-- store object
append arrSegs obj
-- lookat
if trgObj == unsupplied do trgObj = arrSegs[arrSegs.count]
obj.target = trgObj
obj
)
function removeSegment =
(
-- object
local obj = arrSegs[arrSegs.count]
-- create a dummy target, or else 2 nodes get deleted!
local d = dummy ishidden:true
obj.target = d
-- kill objects
delete obj
arrSegs.count = arrSegs.count - 1
)
function setup =
(
-- new scene
delete objects
-- create target
mouseObj = point()
append arrObjs mouseObj
hide mouseObj
-- create objects
local obj, trgObj = mouseObj
for i = 1 to segCount do
(
trgObj = addSegment trgObj:trgObj
trgObj.pos = [0, -i * 30, 0]
)
arrSegs[1].wirecolor = black
-- gameboard
local mat = standardmaterial name:"Gameboard"
local map = mat.diffuseMap = Bricks()
map.coords.V_Tiling = 2
map.coords.U_Tiling = 2
showtexturemap mat map on
local p = plane width:boardSize length:boardSize pos:[0,0,-10] material:mat name:"Gameboard" wirecolor:black lengthsegs:30 widthsegs:30
if boardIsBumpy == true do
(
p.lengthsegs = 50
p.widthsegs = 50
addModifier p (NoiseModifier())
n = p.modifiers[1]
n.strength = [0,0,100]
n.scale = 300
)
--converttopoly p
append arrObjs p
when select $Gameboard changes do deselect $Gameboard
-- camera
local c = freecamera ishidden:true
c.pos = [0,-300,200]
rotate c (angleaxis 70 [1,0,0])
c.fov = 80
c.parent = arrSegs[1]
append arrObjs c
--hide c
-- lights
local l1 = omnilight pos: [-2000,2000,-100] multiplier:1.0 color:white ishidden:true
local l2 = omnilight pos: [2000,-2000,-100] multiplier:0.5 color:(color 150 150 255) ishidden:true
append arrObjs l1
append arrObjs l2
local spot = freespot pos: [0,-100,300] hotspot:50 falloff:120 ishidden:true
rotate spot (angleaxis 35 [1,0,0])
spot.parent = arrSegs[1]
append arrObjs spot
-- viewports
viewport.setLayout #layout_3vl --#layout_2v
viewport.activeViewport = 1
viewport.setType #view_top
viewport.SetRenderLevel #flat
viewport.setGridVisibility 1 false
viewport.activeViewport = 2
viewport.setType #view_persp_user
viewport.setTM (matrix3 [0.713251,-0.532976,0.455204] [0.700909,0.54236,-0.463219] [0,0.649448,0.760406] [-24.3243,333.06,-4051.52])
viewport.SetRenderLevel #smoothhighlights
viewport.setGridVisibility 2 false
viewport.activeViewport = 3
viewport.setType #view_camera
viewport.SetRenderLevel #smoothhighlights
viewport.setGridVisibility 3 false
max tool zoomextents all
-- new pill
createPills 10
-- start
tmr1.active = false
ckbTimer.checked = tmr1.active = queryBox "Start game!?"
)
function follow trg src strict:true =
(
local p = trg.pos - src.pos
local np = normalize p
local mp
local d = distance [0,0,0] p
local fd = src.height * 2
--format "%
" p
if d > fd do
(
if strict then
(
mp = p - np * fd
--mp = np * fd
src.pos += mp
)
else(
mp = np * fd
src.pos += mp
)
)
)
function animateObjects =
(
-- mouse
mouseObj.pos = getMousePos()
-- move
follow mouseObj arrSegs[1] strict:false
--if boardIsBumpy == true do moveToSurface arrSegs[1] $Gameboard
for i = 1 to arrSegs.count - 1 do
(
local trgObj = arrSegs[i]
local srcObj = arrSegs[i + 1]
if isValidNode srcObj do
(
follow trgObj srcObj
if boardIsBumpy == true do moveToSurface srcObj $Gameboard
)
)
)
function killPill pill =
(
deleteItem arrPills (findItem arrPills pill)
delete pill
)
function eatPill pill =
(
removeSegment()
killPill pill
createPills 2
)
function createPills n =
(
for i = 1 to n do
(
local s = sphere()
local v = boardSize * 0.4
s.pos = random [-v, -v, 0] [v, v, 0]
s.wirecolor = white
append arrPills s
if boardIsBumpy == true do
(
moveToSurface s $Gameboard
s.pos.z += s.radius
)
)
)
function checkPills =
(
local endLoop = false
for pill in arrPills do
(
-- eat!
if intersects pill arrSegs[1] do
(
eatPill pill
exit
)
-- hit!
for i = 2 to arrSegs.count do
(
if intersects arrSegs[i] pill do
(
addSegment col:orange
addSegment col:orange
killPill pill
createPills 2
endLoop = true
exit
)
/*
*/
)
if endLoop do exit
)
)
function checkReinstateCollisions =
(
if isColliding == true do
(
counter += 1
if counter == counterMax do
(
isColliding = false
counter = 0
)
)
)
function checkCollisions =
(
local n = 1
for i = 1 to arrSegs.count do
(
for j = n to arrSegs.count do
(
--format "% % %
" i j n
if i == j do continue
if (distance arrSegs[i] arrSegs[j]) < arrSegs[i].width do
(
addSegment col:yellow
addSegment col:yellow
--print arrSegs[i]
--print arrSegs[j]
isColliding = true
exit
)
if isColliding do exit
)
if isColliding do exit
n += 1
)
)
function checkBounds =
(
/*
*/
local p = arrSegs[1].pos
if p.x > $gameboard.max.x OR p.x < $gameboard.min.x OR p.y > $gameboard.max.y OR p.y < $gameboard.min.y do
(
messagebox "You went out of bounds!"
cleanup()
setup()
)
)
function checkSegs =
(
if arrSegs.count == 1 do
(
messagebox "Well done! You ate enough pills!"
cleanup()
setup()
)
)
function cleanup =
(
tmr1.active = false
delete mouseObj
for seg in arrSegs do
(
try(delete seg);catch(err)
)
for pill in arrPills do
(
try(delete pill);catch(err)
)
for obj in arrObjs do
(
try(delete obj);catch(err)
)
arrSegs = #()
arrPills = #()
arrObjs = #()
SetUIColor 41 (GetDefaultUIColor 41)
)
on roMAXSnake open do
(
SetUIColor 41 [0,0,0]
colorMan.repaintUI #repaintAll
setup()
)
on roMAXSnake close do
(
cleanup()
colorMan.repaintUI #repaintAll
viewport.setLayout vptLayout
)
on ckbTimer changed state do tmr1.active = state
on tmr1 tick do
(
animateObjects()
checkPills()
checkCollisions()
checkReinstateCollisions()
checkBounds()
checkSegs()
)
on btnRestart pressed do
(
cleanup()
setup()
)
)
createdialog roMAXSnake
rubik’s cube works here in 2009 as well; cute
One thing you may wish to consider is the transform locks, so that a given ‘twist’ control can only rotate around its appropriate axis
Hey Martin,
Not happy in max 9, but happy in 2008!
It would be great if you would animate the turns, using a timer. The flick is a bit sudden for me.
Glad you like the snake game, and yes, it can be a bit hard to control!
The trick is to put your mouse on the spot on the board you want to travel to (in any viewport) as it’s projecting a ray there, then I’m doing some trig to get the direction.
Great challenge, I’m glad I could take part this time
ok, i discided to write a space invaders game for max. works in max 2008
few bugs in it:
*Script returns a game_setup = undefined at first launch
SOLOUTION: Close down rollout and re-run script
*Script tries to access deleted scene objects when the exit button is pressed and then the start button (ends up crashing max)
SOLOUTION: Dont do it. close down rollout and re-run script
--Classic space invaders in 3d max
--Creator: Geoffrey Samuel
--Contact E-mail: Geoff@GeoffSamuel.com
--Contact Website: [www.GeoffSamuel.com]( http://www.geoffsamuel.com/)
--script wirten, tested and designed by Geoffrey Samuel, all rights reserved 2008.
--KNOW BUGS:
-- *Script returns a game_setup = undefined at first launch
-- SOLOUTION: Close down rollout and re-run script
-- *Script tries to access deleted scene objects when the exit button is pressed and then the start button (ends up crashing max)
-- SOLOUTION: Dont do it. close down rollout and re-run script
fn define_varibals = (
global game_has_started = false
global alien_move_dir = "Right"
global level = 1
global shot=#()
global boxpos
global score= 0
global alien_shots_to_be_deleted =#()
global alien_ship_to_be_deleted =#()
global shots_to_be_deleted =#()
global Shoot_HOLDUP = "1"
global Alien_shot = #()
global Player_level = 0
global level_up_timer_on = true
global timer_wait = 1
global lifes = 3
)
fn game_setup =(
------------------------------------------------------BLOCKS
global blocks = #()
--Set up blocks
blocks[1] = Rectangle length:30.4029 width:18.315 cornerRadius:0 pos:[-156.227,-86.4469,0.2]
blocks[2] = Rectangle length:30.4029 width:18.315 cornerRadius:0 pos:[-110.727,-86.4469,0.2]
blocks[3] = Rectangle length:30.4029 width:18.315 cornerRadius:0 pos:[-65.2271,-86.4469,0.2]
blocks[4] = Rectangle length:30.4029 width:18.315 cornerRadius:0 pos:[-19.7271,-86.4469,0.2]
blocks[5] = Rectangle length:30.4029 width:18.315 cornerRadius:0 pos:[25.7729,-86.4469,0.2]
blocks[6] = Rectangle length:30.4029 width:18.315 cornerRadius:0 pos:[71.2729,-86.4469,0.2]
blocks[7] = Rectangle length:30.4029 width:18.315 cornerRadius:0 pos:[116.773,-86.4469,0.2]
blocks[8] = Rectangle length:30.4029 width:18.315 cornerRadius:0 pos:[162.273,-86.4469,0.2]
for n = 1 to 8 do (
blocks[n].wirecolor = green
convertTo blocks[n] (Editable_Poly)
addModifier blocks[n] (shell innerAmount:0 outerAmount:0.5)
addModifier blocks[n] (subdivide manualUpdate:1 size:35)
)
------------------------------------------------------PLAYER
--makes a new varibal to hold the LINE (SPLINE) data
global Player_ship = line()
--converts the line to a editable spline so vertexs (knots) can be added
convertToSplineShape(Player_ship)
--adds a new spline section to the line
addNewSpline Player_ship
--creates the outline of the player ship
addKnot Player_ship 1 #corner #curve [-29.487,-120.004,0]
addKnot Player_ship 1 #corner #curve [-29.487,-129.853,0]
addKnot Player_ship 1 #corner #curve [-0.549,-129.853,0]
addKnot Player_ship 1 #corner #curve [-0.601,-119.94,0]
addKnot Player_ship 1 #corner #curve [-10.031,-119.94,0]
addKnot Player_ship 1 #corner #curve [-10.031,-116.761,0]
addKnot Player_ship 1 #corner #curve [-13.131,-116.761,0]
addKnot Player_ship 1 #corner #curve [-13.131,-114.103,0]
addKnot Player_ship 1 #corner #curve [-16.428,-114.103,0]
addKnot Player_ship 1 #corner #curve [-16.428,-116.667,0]
addKnot Player_ship 1 #corner #curve [-19.963,-116.667,0]
addKnot Player_ship 1 #corner #curve [-19.963,-119.963,0]
--closes the spline off so it keeps looping
close Player_ship 1
--updates the shape so it can be displayed in the viewport
updateShape(Player_ship)
--gives the player ship that classic green colour
Player_ship.wirecolor = green
-- center the player ship
CenterPivot Player_ship
--select it to apply an edit mesh and a subdeive to it
convertTo Player_ship (Editable_Poly)
addModifier Player_ship (subdivide manualUpdate:1 size:35)
--positon the ship where it should start from
Player_ship.pos = [0,-127.463,0]
global orignal_shot = (Rectangle length:12.0879 width:1.4652 cornerRadius:0 pos:Player_ship.pos wirecolor:WHITE)
convertTo orignal_shot (Editable_Poly)
addModifier orignal_shot (shell innerAmount:0 outerAmount:1)
addModifier orignal_shot (subdivide manualUpdate:1 size:35)
orignal_shot.pos = [727.694,-559.594,0]
--makes a new varibal to hold the LINE (SPLINE) data
global alien_shot_orginal = line()
--converts the line to a editable spline so vertexs (knots) can be added
convertToSplineShape(alien_shot_orginal)
--adds a new spline section to the line
addNewSpline alien_shot_orginal
--creates the outline of the alien shot
addKnot alien_shot_orginal 1 #corner #curve [-111.647,13.54,0]
addKnot alien_shot_orginal 1 #corner #curve [-106.363,13.54,0]
addKnot alien_shot_orginal 1 #corner #curve [-110.212,6.756,0]
addKnot alien_shot_orginal 1 #corner #curve [-104.928,5.908,0]
addKnot alien_shot_orginal 1 #corner #curve [-109.69,-3.486,0]
addKnot alien_shot_orginal 1 #corner #curve [-113.539,-3.42,0]
addKnot alien_shot_orginal 1 #corner #curve [-110.077,3.311,0]
addKnot alien_shot_orginal 1 #corner #curve [-115.27,4.688,0]
--closes the spline off so it keeps looping
close alien_shot_orginal 1
--updates the shape so it can be displayed in the viewport
updateShape(alien_shot_orginal)
--gives the alien shot a yellow colour
alien_shot_orginal.wirecolor = Yellow
-- center the alien shot
CenterPivot alien_shot_orginal
--select it to apply an edit mesh and a subdeive to it
convertTo alien_shot_orginal (Editable_Poly)
addModifier alien_shot_orginal (shell innerAmount:0 outerAmount:1)
addModifier alien_shot_orginal (subdivide manualUpdate:1 size:35)
--positon the ship where it should start from
alien_shot_orginal.pos = [827.694,-459.594,0]
hide alien_shot_orginal
------------------------------------------------------GUI parts
--LIVES
--copy the low res player ship for the lives indicators
global life_1 = instance Player_ship
global life_2 = instance Player_ship
global life_3 = instance Player_ship
--position the lives indicators where they should be
life_1.pos = [95.95,134.28,0]
life_2.pos = [131.973,134.28,0]
life_3.pos = [168.756,134.28,0]
--gives the lives ship that classic green colour
life_1.wirecolor = green
life_2.wirecolor = green
life_3.wirecolor = green
--Lives text
Lives_text = text size:29.21 pos:[44.157,126.741,0] Text: "LIVES" Wirecolor: White font: "OCR A Extended" kerning: -3.84
convertTo Lives_text (Editable_Poly)
--Score text (word score)
score_text = text size:29.21 pos:[-158.072,126.741,0] Text: "SCORE" Wirecolor: White font: "OCR A Extended" kerning: -3.84
convertTo score_text (Editable_Poly)
--Player Score text
global player_score_text = text size:29.21 pos:[-88.109,126.741,0] Text: "0" Wirecolor: green font: "OCR A Extended" kerning: -3.84
)
fn create_aliens = (
------------------------------------------------------SPACE INVADERS
-------make the aliens
--makes a new varibal to hold the LINE (SPLINE) data
alien_ship = line()
--converts the line to a editable spline so vertexs (knots) can be added
convertToSplineShape(alien_ship)
--adds a new spline section to the line
addNewSpline alien_ship
--creates the outline of the player ship
addKnot alien_ship 1 #corner #curve [-158.681,121.033,0]
addKnot alien_ship 1 #smooth #curve [-167.002,108.471,0]
addKnot alien_ship 1 #corner #curve [-163.279,107.176,0]
addKnot alien_ship 1 #corner #curve [-167.002,100.992,0]
addKnot alien_ship 1 #corner #curve [-166.614,100.992,0]
addKnot alien_ship 1 #corner #curve [-162.761,107.047,0]
addKnot alien_ship 1 #corner #curve [-160.624,107.111,0]
addKnot alien_ship 1 #corner #curve [-162.016,104.456,0]
addKnot alien_ship 1 #corner #curve [-161.369,104.456,0]
addKnot alien_ship 1 #corner #curve [-159.912,107.047,0]
addKnot alien_ship 1 #corner #curve [-157.45,107.047,0]
addKnot alien_ship 1 #corner #curve [-155.993,104.456,0]
addKnot alien_ship 1 #corner #curve [-155.346,104.456,0]
addKnot alien_ship 1 #corner #curve [-156.738,107.111,0]
addKnot alien_ship 1 #corner #curve [-154.601,107.047,0]
addKnot alien_ship 1 #corner #curve [-150.748,100.992,0]
addKnot alien_ship 1 #corner #curve [-150.36,100.992,0]
addKnot alien_ship 1 #corner #curve [-154.083,107.176,0]
addKnot alien_ship 1 #smooth #curve [-150.36,108.471,0]
--closes the spline off so it keeps looping
close alien_ship 1
--updates the shape so it can be displayed in the viewport
updateShape(alien_ship)
--gives the player ship that classic green colour
alien_ship.wirecolor = white
-- center the player ship
CenterPivot alien_ship
--select it to apply an edit mesh and a subdeive to it
convertTo alien_ship (Editable_Poly)
addModifier alien_ship (subdivide manualUpdate:1 size:35)
--positon the ship where it should start from
alien_ship.pos = [-163.361,111.534,0]
------populate the alien side
global alien_ships_array = #()
for side = 0 to 4 do (
num_side = side * 11
for top = 0 to 10 do (
num = num_side+top+1
alien_ships_array[num] = instance alien_ship
alien_ships_array[num].wirecolor = color 255 255 255
move alien_ships_array[num] [(top*26.5326),(side*-22.2702),0]
)
)
delete alien_ship
)
fn game_exit = (
viewport.ResetAllViews()
mybox = box()
togo = max select all
if togo != undefined then (
delete $
)
)
fn alient_check_dir = (
if alien_ships_array[1].pos.x > -77.976 then (
for p = 1 to alien_ships_array.count do (
move alien_ships_array[p] [0,-22.2702,0]
)
alien_move_dir = "Left"
level += 0.025
)
if alien_ships_array[1].pos.x < -189.617 then (
for p = 1 to alien_ships_array.count do (
move alien_ships_array[p] [0,-11.1351,0]
)
alien_move_dir = "Right"
level += 0.025
)
)
fn aliens_move= (
--move left
if alien_move_dir == "Right" do(
for p = 1 to alien_ships_array.count do (
move alien_ships_array[p] [level,0,0]
))
--move right
if alien_move_dir == "Left" do(
for p = 1 to alien_ships_array.count do (
move alien_ships_array[p] [-level,0,0]
))
)
fn shooting = (
if Shoot_HOLDUP =="1" do (
append shot (instance orignal_shot)
Shoot_HOLDUP="0"
)
)
tool moveplayer (
on freeMove do(
Player_ship.pos.x = worldPoint.x
if Player_ship.pos.x > 185.357 do (
Player_ship.pos.x =185.356)
if Player_ship.pos.x < -186.598 do (
Player_ship.pos.x =-186.597)
)
on mouseMove clickno do (
Player_ship.pos.x = worldPoint.x
if Player_ship.pos.x > 185.357 do (
Player_ship.pos.x =185.356)
if Player_ship.pos.x < -186.598 do (
Player_ship.pos.x =-186.597)
orignal_shot.pos = Player_ship.pos
hide orignal_shot
)
on mousePoint click do(
shooting()
if mButton do batchFloater.pos = boxpos
))
fn wall_shot_detection shot_num = (
for b = 1 to blocks.count do (
if (distance shot[shot_num] blocks[b]) < 15 then (
global nVertsBefore = blocks[b].mesh.numVerts
global nVertsAfter = (blocks[b]- shot[shot_num]).numverts
if nVertsBefore==nVertsAfter then(
)else (
--print "collision"
append shots_to_be_deleted shot_num )
)
)
)
fn alien_shot_detection shot_num= (
for p = 1 to alien_ships_array.count do (
if (distance shot[shot_num] alien_ships_array[p]) < 20 then (
global nVertsBefore = shot[shot_num].mesh.numVerts
global nVertsAfter = ( shot[shot_num] - alien_ships_array[p]).numverts
if nVertsBefore!=nVertsAfter then(
--print "no collision"
)
else
(
--print "collision"
if p==1 then (
hide alien_ships_array[p]
score+=10
append shots_to_be_deleted shot_num
)
else
(
append alien_ship_to_be_deleted p
print number_of_aliens_killed
score+=10
append shots_to_be_deleted shot_num
exit
)
)
)
)
)
fn alien_shooting = (
ship_to_shoot = (random 2 alien_ships_array.count)
alien_shot_orginal.pos = alien_ships_array[ship_to_shoot].pos
append Alien_shot (instance alien_shot_orginal)
)
fn ALIEN_wall_shot_detection= (
for p = 1 to Alien_shot.count do (
for b = 1 to blocks.count do (
if (distance Alien_shot[p] blocks[b]) < 8 then (
global nVertsBefore = blocks[b].mesh.numVerts
global nVertsAfter = (blocks[b] - Alien_shot[p]).numverts
if nVertsBefore==nVertsAfter then(
append alien_shots_to_be_deleted p
)else (
print "collision"
--append alien_shots_to_be_deleted p
)
)
)
)
)
fn ALIEN_shot_to_player_detection = (
for p = 1 to Alien_shot.count do (
if (distance Alien_shot[p] Player_ship) < 20 then (
global nVertsBefore = Alien_shot[p].mesh.numVerts
global nVertsAfter = ( Alien_shot[p] - Player_ship).numverts
if nVertsBefore!=nVertsAfter then(
--print "no collision"
)
else
(
append alien_shots_to_be_deleted p
lose_life()
)
)
)
)
fn lose_life = (
lifes -=1
if lifes == 2 do hide life_3
if lifes == 1 do hide life_2
if lifes == 0 do hide life_1
if lifes < 0 do gameover()
)
fn gameover = (
game_has_started = false
global gameover_text = text size:69.0 kerning:0 leading:0 pos:[3.11355,-14.8352,50] text: "GAME OVER"
convertTo gameover_text (Editable_Poly)
batchFloater.pos = boxpos
)
fn level_up = (
level_up_timer_on = true
create_aliens()
number_of_aliens_killed =0
level +=0.1
Player_level +=1
Player_level_string = "LEVEL " + Player_level as string
global level_text = text size:100 kerning:0 leading:0 pos:[3.11355,-14.8352,50] text: Player_level_string
convertTo level_text (Editable_Poly)
)
rollout Batch_Converter "SPACE INVADERS" width:200 height:80
(
button Start "START" pos:[13,6] width:179 height:22
button exit_button "EXIT" pos:[7,32] width:189 height:41
timer Level_up_timer "Timer" pos:[94,67] width:24 height:24 interval: 2000
timer Shoot_HOLDUP_timer "Timer" pos:[94,67] width:24 height:24 interval: 250
timer shoot_timer "Timer" pos:[94,67] width:24 height:24 interval: 40
timer player_timer "Timer" pos:[94,67] width:24 height:24 interval: 40
timer alients_timer "Timer" pos:[94,67] width:24 height:24 interval: 40
timer score_timer "Timer" pos:[94,67] width:24 height:24 interval: 150
timer alien_shoot_timer "Timer" pos:[94,67] width:24 height:24 interval: 500
on Shoot_HOLDUP_timer tick do
(
Shoot_HOLDUP = "1"
)
on alien_shoot_timer tick do
(
if game_has_started == true then (
alien_shooting()
)
)
on Level_up_timer tick do
(
if level_up_timer_on == true do (
timer_wait += 1
if timer_wait == 2 do (
level_up_timer_on = False
delete level_text
timer_wait = 0
)
)
)
on score_timer tick do
(
if game_has_started == true then (
player_score_text.text = (score as string)
if alien_ships_array.count<=1 do (
level_up()
)
)
)
on player_timer tick do
(
if game_has_started == true then (
startTool moveplayer
stopTool moveplayer
)
else (stopTool moveplayer)
)
on shoot_timer tick do
(
if game_has_started == true then (
alien_ship_to_be_deleted =#()
shots_to_be_deleted =#()
alien_shots_to_be_deleted =#()
ALIEN_shot_to_player_detection()
for r=1 to shot.count do (
alien_shot_detection r
wall_shot_detection r
)
for q=1 to alien_shots_to_be_deleted.count do (
if Alien_shot[alien_shots_to_be_deleted[q]] != undefined do(
delete Alien_shot[alien_shots_to_be_deleted[q]]
deleteItem Alien_shot alien_shots_to_be_deleted[q]
))
alien_shots_to_be_deleted =#()
ALIEN_wall_shot_detection()
for q=1 to alien_shots_to_be_deleted.count do (
if Alien_shot[alien_shots_to_be_deleted[q]] != undefined do(
delete Alien_shot[alien_shots_to_be_deleted[q]]
deleteItem Alien_shot alien_shots_to_be_deleted[q]
))
alien_shots_to_be_deleted =#()
for r=1 to Alien_shot.count do (
if Alien_shot[r].pos.y < -178.815 then (
append alien_shots_to_be_deleted r
)
)
for q=1 to alien_shots_to_be_deleted.count do (
if Alien_shot[alien_shots_to_be_deleted[q]] != undefined do(
delete Alien_shot[alien_shots_to_be_deleted[q]]
deleteItem Alien_shot alien_shots_to_be_deleted[q]
))
for p=1 to alien_ship_to_be_deleted.count do (
if alien_ships_array[alien_ship_to_be_deleted[p]] != undefined do(
delete alien_ships_array[alien_ship_to_be_deleted[p]]
deleteItem alien_ships_array alien_ship_to_be_deleted[p]
))
for y=1 to shots_to_be_deleted.count do (
if shot[shots_to_be_deleted[y]] != undefined do(
delete shot[shots_to_be_deleted[y]]
deleteItem shot shots_to_be_deleted[y]
)
)
shots_to_be_deleted =#()
for r=1 to shot.count do (
wall_shot_detection r
)
for y=1 to shots_to_be_deleted.count do (
if shots_to_be_deleted[y] != undefined do(
delete shot[shots_to_be_deleted[y]]
deleteItem shot shots_to_be_deleted[y]
) )
shots_to_be_deleted =#()
for r=1 to shot.count do (
if shot[r].pos.y > 155.49 then (
append shots_to_be_deleted r
)
)
for y=1 to shots_to_be_deleted.count do (
delete shot[shots_to_be_deleted[y]]
deleteItem shot shots_to_be_deleted[y]
)
for s=1 to shot.count do (
move shot[s] [0,10,0]
shot[s].wirecolor = WHITE
)
for j=1 to Alien_shot.count do (
move Alien_shot[j] [0,-10,0]
Alien_shot[j].wirecolor = YELLOW
)
)
)
on alients_timer tick do
(
if game_has_started == true then (
alient_check_dir()
aliens_move()
)
)
on Start pressed do
(
game_start()
boxpos = batchFloater.pos
batchFloater.pos = [1301,447]
level_up()
)
on exit_button pressed do
(
game_has_started = false
stopTool moveplayer
game_exit()
)
)
fn game_start = (
game_exit()
define_varibals()
viewport.setLayout #layout_1
viewport.setType #view_top
viewport.SetRenderLevel #smoothhighlights
viewport.setGridVisibility #all false
DisableSceneRedraw()
game_setup()
clearSelection()
EnableSceneRedraw()
ResetXForm Player_ship
game_has_started = true
)
function MakerolloutFloat =
(
global batchFloater = newRolloutFloater "space invaders" 220 109
addRollout Batch_Converter batchFloater rolledup:false
)
MakerolloutFloat()
references:
- the maxscript reference
- The collion detection theroy from a post here on CGSociety