Home Technical Talk

Maxscript - EPoly face index out of range

Novian
polycounter lvl 5
Offline / Send Message
Novian polycounter lvl 5
Gents,

I was wondering if I could trouble you for help on another Maxscript question. My progress on the flipping tiles animated bumper is going well but I have hit a snag. Below is the section of code that I am having an issue with:
select $Tile_*

GTiles = $ as Array

--print GTiles

clearselection()

select $WAVE

numfaces = selection[1].GetNumFaces()

--print numfaces

STime = 0

for t = 0 to 9 do
(
	sliderTime = STime

	for x = 1 to numfaces do
	(
		$.EditablePoly.SetSelection #Face #{x}
		
		plycenter = polyOp.getsafefacecenter $ x
	
		for obj in GTiles where obj.pos == plycenter do
		(
			select obj
			print obj
		)
	)
	
	STime = STime + 1
)

The issue is this, when I run the code it should: progress through the timeline for the length of the WAVE object's animation. For each frame it loops through each face of the WAVE object and compares each face's position to the GTiles (Get tiles) array looking for a match. If there is a match then we would go on to begin that tile's animation. In my very simple example here the first two frames pass without a "hit" but then the third frame (frame 2 actually due to 0 index) we have one face that indeed overlaps one of the tiles. This is where I receive an error in the MaxScript Listener.

The error I keep getting reads:
-- Error occurred in x loop; filename: C:\Program Files (x86)\Autodesk\3ds Max 9\Scripts\Test1.ms; position: 335
--  Frame:
--   x: 2
--   called in t loop; filename: C:\Program Files (x86)\Autodesk\3ds Max 9\Scripts\Test1.ms; position: 432
--  Frame:
--   t: 2
-- Runtime error: EPoly face index out of range:  < 1 or > 1: 2
OK



The concept is to have a master wave shape that will "look" beneath itself and animated any of the tiles that it passes over. Note: The master shape is animated to move exactly one tile per frame.

Attached are two images that show the initial state followed by when the error occurs.



Any help you all could provide would be most appreciated.


Cheers~

Replies

  • leslievdb
    Options
    Offline / Send Message
    leslievdb polycounter lvl 15
    do you have an edit poly modifier on top of that wave object?

    i'm guessing you used the edit_poly modifier to be able to keep the entire plane on the bottom of the modifier stack in case you want to do some variation of control tiles

    try this
    numfaces = selection[1].modifiers[#Edit_Poly].GetNumFaces()
    also you are changing your selection if it hits so that will give you errors
    here's an updated version that should work
    select $Tile_*

    GTiles = $ as Array

    --print GTiles

    numfaces = $WAVE.modifiers[#Edit_Poly].GetNumFaces()
    print numfaces

    STime = 0

    for t = 0 to 5 do
    (
    sliderTime = STime

    for x = 1 to numfaces do
    (
    $WAVE.modifiers[#Edit_Poly].Select #Face #{x}

    plycenter = polyOp.getsafefacecenter $WAVE x

    for obj in GTiles where obj.pos == plycenter do
    (
    select obj
    print obj
    )
    )

    STime = STime + 1
    )
  • Novian
    Options
    Offline / Send Message
    Novian polycounter lvl 5
    @Ravenslayer: Thanks very much for your help! Using your advice I have made some more great progress. The tiles are now animated with the proper offset however a small glitch remains.

    The following is my current code:
    select $Tile_*

    GTiles = $ as Array

    --print GTiles

    numfaces = $WAVE.GetNumFaces()
    --print numfaces

    STime = 0

    for t = 0 to 9 do
    (
    sliderTime = STime

    for x = 1 to numfaces do
    (
    polyop.SetFaceSelection $WAVE #(x)

    plycenter = polyOp.getsafefacecenter $WAVE x

    for obj in GTiles where obj.pos == plycenter do
    (
    --Turn on animate
    set animate on

    --Set obj sliderTime to equal t
    sliderTime = t

    --Set a keyframe
    obj.EditablePoly.buttonOp #bevel

    --Move the sliderTime to the current frame plus 30
    sliderTime = (STime + 30 + (t*2))

    --Rotate the tile
    rotate obj (angleaxis 180 [1,0,0])

    --Set a keyframe
    obj.EditablePoly.buttonOp #bevel

    --Turn off animate
    set animate off

    --Return the sliderTime to the current frame
    sliderTime = STime
    --print obj
    )
    )

    STime = STime + 1
    )

    The tiles are properly selected and animated however their start frame remains at 0. It should begin at whatever frame t is at, which is the animation frame of the WAVE object.

    Again thanks very much for all the help guys. I hope everyone had or is having a good holiday.

    Cheers~
  • leslievdb
    Options
    Offline / Send Message
    leslievdb polycounter lvl 15
    that's because you only set one key , by default the "Default In/Out tangents for new keys" is set to linear, if you change that to stepped and then run your script it will only change on the time keys are set. (3rd one in the picture)

    image014.gif
  • Novian
    Options
    Offline / Send Message
    Novian polycounter lvl 5
    @Ravenslayer: Thanks, I tried that but no change. The good news that came of it is that I could clearly see that once it does work the effect will be wonderful. When I make the change you suggested with the default set to step I see no movement in the tiles until the frame that it flips (instatly). However the first frame of each tile's animation is still always 0.

    As always any assitance as well as all your help so far, it most appreciated.

    I'm learning a lot about Maxscript as a result! :) It's fun but can be frustrating.

    Cheers~
  • leslievdb
    Options
    Offline / Send Message
    leslievdb polycounter lvl 15
    what you need to do is set the first key where you want it then. So if you want to animate it in lets say 4 frames you do something like this
    --Rotate the tile
    at time (t-3) rotate obj (angleaxis 0 [1,0,0])
    at time t rotate obj (angleaxis 180 [1,0,0])
    do make sure you don't use the stepped mode then
  • Novian
    Options
    Offline / Send Message
    Novian polycounter lvl 5
    @Raven: That worked! Many thanks! :)

    Cheers~
  • leslievdb
    Options
    Offline / Send Message
    leslievdb polycounter lvl 15
    np , had to look up the keyframing bit myself so i also learned something new ^^
  • Novian
    Options
    Offline / Send Message
    Novian polycounter lvl 5
    It appears that I still have more to learn. While the code works on my small sample scene it is not working on the master scene. The following is my code:
    select $Tile_*
    
    GTiles = $ as Array
    
    --print GTiles
    
    numfaces = $WAVE.GetNumFaces()
    --print numfaces
    
    STime = 0
    
    --clearselection()
    
    for t = 0 to 132 do
    (
    	sliderTime = STime
    
    	for x = 1 to numfaces do
    	(
    		polyop.SetFaceSelection $WAVE #(x)
    		
    		plycenter = polyOp.getsafefacecenter $WAVE x
    	
    		for obj in GTiles where obj.pos == plycenter do
    		(
    			--Turn on animate
    			set animate on
    			
    			--Set a keyframe
    			--obj.EditablePoly.buttonOp #bevel
    			at time (t) rotate obj (angleaxis 0 [1,0,0])
    			
    			--Move the sliderTime to the current frame plus 30
    			--sliderTime = (STime + 30 + (t*2))
    			at time (STime + 30 + (t*2)) rotate obj (angleaxis 180 [1,0,0])
    			
    			--Turn off animate
    			set animate off
    			
    			--Return the sliderTime to the current frame
    			sliderTime = STime
    			--print obj
    		)
    	)
    	
    	STime = STime + 1
    )
    

    The WAVE object moves across the "map" however no tile is ever selected or animated.

    Much appreciated for any suggestions.

    Cheers~
  • cw
    Options
    Offline / Send Message
    cw polycounter lvl 17
    share the scene and I can look at it for you. I'm not 100% clear what your goal is precisely or what stuff I need in the scene to see it working.

    cheers,
    cw
  • Novian
    Options
    Offline / Send Message
    Novian polycounter lvl 5
    @cw: Thanks for the offer! Please use the following link to download the file from my website:

    http://www.mentallic.com/download/World_Tile_Flip_Work6.max

    The goal is to have the WAVE object move across the world map tiles. The WAVE object moves exactly one tile's width each frame. For each frame the script checks the center of each face of the WAVE object. It then compares that face's center to the center of any tile that happens to be at that location. If there is a match then the tile is selected to begin it's animation (30 frames 180 degree turn north to south with a 3 frame delay before the next set of tiles begin their turn)

    In the end the desired effect is similar to the "card flipping" seen at sporting events only in this instance the pixelated world appears on the surface of the logo.

    Thanks for all the help guys.

    Cheers~
  • cw
    Options
    Offline / Send Message
    cw polycounter lvl 17
    (
        fn pos_very_close_2 _p1 _p2 _tolerance:0.01=
        (
            --compare only on XZ plane, logically y is always 0
            if (abs(_p2.x-_p1.x)<_tolerance) and (abs(_p2.z-_p1.z)<_tolerance) then 
            (
                --format "close enough!\n"
                return true
            )
            else 
            (
                return false
            )
        )
        
        fn pos_very_close _p1 _p2 _tolerance:0.01=
        (
            offset=length(_p2-_p1)
            if offset<_tolerance then 
            (
                --format "close enough!\n"
                return true
            )
            else 
            (
                return false
            )
        )
    
        waveobj = getnodebyname "WAVE"
    
        if waveobj != undefined then
        (
            GTiles = ($Tile_* as Array)
            --print GTiles
            numfaces = waveobj.GetNumFaces()
            --print numfaces
    
            STime = 0
            endtime = 132
            --clearselection()
    
            --for t = 0 to 132 do
            for t = STime to endtime do
            (
                sliderTime = t
                --for each frame we can only check tiles which are nearby to the wave.
                -- we can get the tiles within the bounding box-ish area, 
                --it speeds up the face loop quite a bit.
                box pos:waveobj.center height:500 length:50 width:(waveobj.max-waveobj.min).x
                --the x values to base the cull on - 
                aabb = waveobj.max-waveobj.min
                check_min = waveobj.center.x - (aabb.x/2)
                check_max = waveobj.center.x + (aabb.x/2)
                
                checkobjs = for t in GTiles where ((check_min < t.center.x) and (t.center.x < check_max)) collect t
                
                --for p in checkobjs do (format "%\n" p.name)
                
                --iterate over wave objects faces:
                for x = 1 to numfaces do
                (
                    --get wave object face center for face x
                    polyop.SetFaceSelection waveobj #(x)
                    wave_poly_center = polyOp.getsafefacecenter waveobj x
                
                    --compare with tolerance to allow close points to pass test - max is not super accurate!
                    for obj in checkobjs where (pos_very_close obj.pos wave_poly_center) do
                    (
                        --Turn on animate
                        set animate on
                        
                        --Set a keyframe
                        --obj.EditablePoly.buttonOp #bevel
                        at time (t) rotate obj (angleaxis 0 [1,0,0])
                        
                        --Move the sliderTime to the current frame plus 30
                        --sliderTime = (STime + 30 + (t*2))
                        at time (t + 30) rotate obj (angleaxis 180 [1,0,0])
                        
                        --Turn off animate
                        set animate off
                        
                        --Return the sliderTime to the current frame
                        sliderTime = t
                        --print obj
                    )
                )
                
            )
        )
    )
    
    I changed a couple of things.

    1) I worked in 2011, so maybe it has some effect?

    2) I cleaned up the script a bit, remove $ reference and things like that where possible.

    3) don't try to compare positions exactly, max is not usually so accurate, you need a 'close enough' approacy with a tiny tolerance to get meaningful results.

    4) a tiny optimisation in only checking tiles in the bouding box of the wave, because to check them all was a tad slow.

    Let me know how it works for you (I'm guessing you're on 2012? make sure you have all service packs etc.)
  • Novian
    Options
    Offline / Send Message
    Novian polycounter lvl 5
    @cw: I have Max 9 and will for a while due to some frustrating circumstances, however I greatly appreciate the code and will try it as soon as I can and will get back to you.

    Thanks much for the quick reply!

    Cheers~
  • Novian
    Options
    Offline / Send Message
    Novian polycounter lvl 5
    Many thanks all, the effect is working well. I'll be sure to update you all when I have the finished product.

    Cheers~
  • cw
    Options
    Offline / Send Message
    cw polycounter lvl 17
    yay! happy new year
Sign In or Register to comment.