Simple 3D FPS Movement Demo (moonlit camera in woods)— Revised

@SugarRay Here’s a version of my code that uses buttons.

Replaced below code to reduce button code in button:touched.

viewer.mode=FULLSCREEN

function setup()
    btn={}
    rectMode(CENTER)
    assert(craft, "Include Craft as a dependency")
    ex,ey,ez=0,45,0
    speed,xx,yy=0,0,0
    dir=0
    cameraX,cameraY,cameraZ=-205,1,-205
    scene = craft.scene()
    scene.camera.position = vec3(cameraX,0,cameraZ)
    scene.camera.eulerAngles=vec3(ex,ey,ez)
    scene.sun.rotation = quat.eulerAngles(45,0,45)
    scene.ambientColor = color(90,90,90)   
    skyMaterial = scene.sky.material
    skyMaterial.horizon = color(0, 203, 255, 255)
    mtl = craft.material(asset.builtin.Materials.Standard)
    img = readImage(asset.builtin.Surfaces.Basic_Bricks_AO)    
    createFloor()
    -- create random walls
    for z=1,100 do
        xPos=math.random(-200,200)
        zPos=math.random(-200,200)
        createWall(xPos,zPos,math.random(20,60),.1)
        xPos=math.random(-200,200)
        zPos=math.random(-200,200)
        createWall(xPos,zPos,.1,math.random(20,60))
    end      
    table.insert(btn,button(WIDTH/2-100,100,"Left",function() xx=-.3 end))  
    table.insert(btn,button(WIDTH/2+100,100,"Right",function() xx=.3 end))  
    table.insert(btn,button(WIDTH/2,150,"Forward",function() speed=.1 end))  
    table.insert(btn,button(WIDTH/2,50,"Backward",function() speed=-.1 end))  
    table.insert(btn,button(WIDTH/2-100,150,"Cam Up",function() dir=.1 end))  
    table.insert(btn,button(WIDTH/2-100,50,"Cam Down",function() dir=-.1 end))  
    table.insert(btn,button(WIDTH/2+100,150,"Look Up",function() yy=-.2 end))  
    table.insert(btn,button(WIDTH/2+100,50,"Look Down",function() yy=.2 end))  
end

function draw()
    background(0)
    update(DeltaTime)
    scene:draw()
    updateCameraPos()
    for a,b in pairs(btn) do
        b:draw()
    end
end

function update(dt)
    scene:update(dt)
    scene.camera.position = vec3(cameraX,cameraY,cameraZ)
    scene.camera.eulerAngles=vec3(ex,ey,ez)
end

function touched(t)
    for a,b in pairs(btn) do
        b:touched(t)
    end
end

function updateCameraPos()
    ex=ex+yy
    ey=ey-xx
    x=speed*math.sin(math.rad(ey))
    z=speed*math.cos(math.rad(ey))
    cameraX=cameraX+x
    cameraY=cameraY+dir
    if cameraY<1 then
        cameraY=1
    end
    cameraZ=cameraZ+z    
end

function createFloor()
    local c1=scene:entity()
    c1.model = craft.model.cube(vec3(400,.1,400))
    c1.position=vec3(0,0,0)
    c1.material = craft.material(asset.builtin.Materials.Standard)
    c1.material.map = readImage(asset.builtin.Surfaces.Desert_Cliff_Color)
end

function createWall(xp,zp,xs,zs)
    local c1=scene:entity()   
    c1.material=mtl
    c1.material.map=img
    c1.model=craft.model.cube(vec3(xs,6,zs))
    c1.position=vec3(xp,3,zp)
end

button=class()

function button:init(x,y,n,a)
    self.x=x
    self.y=y
    self.name=n  
    self.action=a  
end

function button:draw()
    fill(255)
    rect(self.x,self.y,90,40)
    fill(0)
    text(self.name,self.x,self.y)
end

function button:touched(t)
    if t.x>self.x-45 and t.x<self.x+45 and t.y>self.y-20 and t.y<self.y+20 then
        if t.state==BEGAN then
            self.action()
        end
        if t.state==ENDED then
            xx,yy,speed,dir=0,0,0,0
        end
    end    
end

Thanks you so much, @dave1707 , your project does exactly what I was looking for in terms of 3D FPS movement! I might do some slight modifications (such as moving the buttons to the bottom sides of the display to mimic more of a thumb joystick control like other FPS games), but I’m now ready to try building some exciting 3D exploration projects! I think I’m going to first build a simple underwater demo where the user is some sort of a diver that can look and move around in 3D while perhaps a shark or other fish swims around the diver.

I also want to thank you for introducing math to me again. I haven’t used trigonometry in over 35 years and there you went and put sin and cos in your project. I was wondering how I might rotate the FPS camera and then move forward after rotating and convert the camera’s x,y,z coordinates to new vectors once I rotate the camera off its z axis by a certain number of degrees and learned that sin and cos provide such information. Little did I know I’d be using trigonometry so many years later…

Have a good night :slight_smile:

@dave1707 , I tried out your FPS controls in the larger 3D Maze model I posted earlier. Works very well (a “3D Maze Fort in the sky”):

https://youtu.be/BvcK7gTE7Fs

I’m also thinking I would prefer the up and down keys to actually rotate the camera position up and down around the x axis (rather than actually elevating the camera position up and down on the y axis as set up in the current project). I think that would provide a more natural human 3D exploratory movement. One would then move forward and back based on whatever 3D orientation the camera is pointing. That would then also seem to provide a natural way to progress up and down stairs in a 3D FPS environment. Will experiment with your project to see what seems to work best.

@SugarRay Glad this works for you. I modified the above code and added 2 more buttons to tilt the camera up or down.

Using the Look up or Look down buttons is very obvious when the camera is moved high above the ground and you look down at the walls.

Thanks, again, @dave1707! I’ll try at your new code. I didn’t know you were going to get to that modification so fast, so I ended making my own modification of the code to accomplish the same thing and then spread out the buttons. I suspect yours will work better than mine but here’s a video showing what I came up with (simple underwater video of a school of mixed fish swimming around— next steps would be to smooth out the movement a little water for more of an underwater feel, add a diver avatar and an ocean bottom):

https://youtu.be/V04wiAurXAw

I’m excited to try out your revised code and explore many new 3D environments with it (haunted mansion, multi-level house, city block) :slight_smile:

PS, @RonJeffries, the fish are circling using the formula you taught in your online Craft tutorial. :slight_smile:

@SugarRay Nice fish demo. Would like to see your other demos when you get them going.

Thanks, @dave1707. Will post them when I’m finished.

Quick question:
Can Codea use non-Codea imported .obj material files? I’ve not been able to get Codea to recognize them and have ended up instead using Codea’s builtin material files.

@SugarRay - Codea can use the established .mtl files for .obj files provided you have the relevant texture files and the .obj and .mtl files conform to their standard format.

Ok, thanks for the information, @Bri_G. Maybe the files I was trying to use didn’t confirm to a standard format— I’ll try again with other models.

Fyi, @Bri_G, I often get errors like on the attached screen shot when I try and run my projects with obj model’s pre-configured .mtl files

@SugarRay - looks like you are missing a shader which must be specified in one of the files, probably the mtl file. You can open obj and mtl files with a text editor - check them out and see if you can edit the shader files out if you post the mtl file I’ll check it out.

Thanks, @Bri_G. Strange, even though the .mtl file is a text file, iOS doesn’t automatically recognize at such (e.g. none of my standard iOS text editors recognize it to open— that’s happened before on some other text files, and I’m not sure why). Anyways, I have one programming app that seems to open anything, and I got it to open. Here is the metal file which seems pretty simple (although I don’t actually know had to interpret the syntax in a .mtl file):

newmtl FG1
d 1
Kd 1 1 1
map_Kd ./Maps/gbr-maori-wrasse04.jpg

newmtl FG2
d 1
Kd 1 1 1
map_Kd ./Maps/gbr-maori-wrasse02.jpg

newmtl FG3
d 1
Kd 1 1 1
map_Kd ./Maps/gbr-maori-wrasse05.jpg

newmtl FG4
d 1
Kd 1 1 1
map_Kd ./Maps/gbr-maori-wrasse01.jpg

newmtl FG5
d 1
Kd 1 1 1
map_Kd ./Maps/crabshell.jpg

I have all the .jpgs and can load them separately onto the model if I use Codea to extract the submESH materials, assign each submESH to a standard Codea mesh shader and then add the .jpgs as a material.map to the standard Codea mesh materials. (The basis of the fish video I uploaded).

I now realize I didn’t try not breaking up the model into submESH and just trying to assign the model’s material to the .mtl file and let the .mtl file attach all of the different textures? I can try that instead if you thought that might be the problem, although I thought I read on the forum that one needs to break up the model into submeshes in order to put multiple textures on one model (i.e. Codea doesn’t have a native ability to use one .mtl file to add on multiple submeshes)

Ah, @Bri_G, I just tried removing the submESH commands and just setting the entire model.material = that .mtl file. That didn’t give me an error, but I didn’t end with any of the .jpg textures applied.

Would do I still need to explicitly tell Codea to load a mapped texture (i.e. entire model.material.map = readImage(.jpg))? I didn’t think that would work without doing submeshes since there are multiple .jpgs that need to be assigned to the model.material.

Or, should Codea be able to just from the model and the model.material = that .mtl file apply the multiple .jpg textures without me having to explicitly assign them to a model.material.map? If that’s supposed to be the case, then maybe it is a path discrepancy between the pre-configured .mtl file instructions and Codea’s own path? For example it looks like at the end of the .mtl file, it is trying to map one of the submESH to the crab shell found at “./Maps/crabshell.jpg”. My crabshell.jpg file is currently stored as asset.Documents.crabshell.jpg which I suspect are not the same paths.

I appreciate any suggestions you might have. It would be nice to be able to use the pre-configured meshes; in addition, it would be nice to not have to manually try and guess which texture go with which sub-meshes and add multiple sub-meshes into the model.material in Codea code.

Thanks :slight_smile:

@Bri_G, I was able to figure out the .mtl issue and answered my own question. It turned out that I was able to get Codea to properly load and properly use the .mtl files without having to set subMeshes directly. The key did seem to be making sure the path/file structure was preserved with what the .mtl file expects and then the .mtl file in Codea loads up all the textures correctly without me having to set each texture to any material.map. It seems then like most .obj models with .mtl and multiple jpg/.png textures usually pack the textures into a certain folder and then the .mtl file just looks for the textures in that folder. Figuring that out makes coding the import of the model so much faster: the next project demo I am working on is an elaborate “haunted mansion” with approximately 128 textures. All I had to do was just import the scene.model as the .obj file, import the scene.material as the .mtl file and then make sure I kept all 128 textures in the original folder they were in when the .obj zip was unzipped, and Codea applied all the textures perfectly :slight_smile:

Thank you and others for your patience in answering my questions as I learn craft. It is very fun. I also wanted to give a shout out to @Ignatz’s 3D tutorial in the Codea wiki. It was a little daunting when I first glanced at it some time ago, but now that I’m getting into craft and figuring out how to move the camera in 3D, I found that Ignatz already explained a lot of how to do such movement in his tutorial.

@SugarRay - sorry I haven’t posted back earlier. You seem to have sorted it out yourself. Yes, the obj and mtl file formats are very tightly defined. You have to be pedantic on making sure the correct paths etc are present.
For Codea now I tend to place the obj, mtl and textures all in the same directory so that naming is easier in the obj and mtl files.

A couple of links covering the file formats conceived by the inventors at Wavefront technologies.

Wikipedia Link

Paul Bourke

Very helpful, thank you, @Bri_G.

@Bri_G,

Now that you helped me figure out the proper .mtl loading, I was able to add the sea bottom to the fish demo. I’ll think you’ll like it (the sea bottom itself is a 400MB model— takes Codea 5-10 sec to load up on my iPad Pro. Still need to smooth out undersea movement):

https://youtu.be/CMP7gx_Vn5g

Cc:
@dave1707 , @binaryblues

@SugarRay that starts to look very nice. You might be interested in my app KM3NeT available for free on the app store. It was also made with Codea and is located at the bottom of the sea. https://apps.apple.com/fr/app/km3net/id1508583421?l=en

You can pilot a rov or crawler around (also in AR).

Why do you load a large model for the seafloor, it could be just a plane with a texture?

Thanks, @piinthesky, I downloaded your app it tried it out. It was great to see a Codea app like yours being used to explain such cutting edge scientific work like detecting neutrinos on the Mediterranean Sea floor. I liked driving around your sea floor and exploring the neutrino collecting equipment. I also really liked your screen joysticks and would prefer a screen joystick over the buttons in the future if you are sometime interested in sharing your code for the on-screen joysticks.

Did you used Codea to also make the app’s “movie”? If so, perhaps for another forum topic, I’d be interesting in learning how you did so.

Sorry I didn’t clarify more about the “sea floor” model I imported. The seafloor model includes the seafloor and 3D coral and sunken boat which I think makes the model file size so large. I agree that if I just needed a sea floor by itself it would have made more sense to just make a plane with a texture.