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

@Bri_G & @Simeon,

The Codea reference discussion on importing .obj .mtl files is a bit confusing to me as a novice. After setting my entity.model = craft.model(.obj model) it seems that if I want to use a built in Codea shader I then do:

entity.material = craft.material(asset.builtin.Materials.standard) etc (as per the reference example).

However, if I want to instead import an .obj objects .mtl file, I do instead:

entity.model.material = craft.model(.mtl file)

I finally figured out the difference after not being able to import .mtl files properly and, in retrospect, do see that the under the craft.model section of the reference there is a note about the model having a material property but I initially mixed them up and was trying to do:

entity.material = craft.material(.mtl file) which gave me a shader load error.

Perhaps it might be helpful to clarify this distinction in the reference of a future Codea release.

Fyi.

@SugarRay - I tend to steer away from shaders, just use the built-in shaders provided by Craft. So there was no confusion with the mtl file, Just needed to make sure models present with mtl file and paths addressed properly. Documentation may need a little editing.

Thanks, @Bri_G.

PS,
One helpful feature about .obj .mtl file paths that I just stumbled upon:

It seems that when the .mtl file looks for the folder containing the texture/maps it actually just looks for a folder that contains the searched for name in the actual folder name. For example, in many of the .obj .mtl files I’ve been using recently, the .mtl file specifies that the folder containing the texture/maps is in a folder called “maps”. I was initially bummed about that since different models I downloaded all named their texture/map folder “maps” and since I store my models and .mtl files and texture/maps local in Codea’s document folder, I thought I had to keep renaming the “maps” folder to the folder I wanted to use for the project I wanted to run. Fortunately, it turns out that I don’t need to do that! Thus, I’ve got multiple map folders named, for example, MapsSeaBottom, MapsMaze, MapsSpace with different texture/maps in them, and all I need to do is import the appropriate .mtl file into my project, and despite that .mtl file specifying that the textures/maps need to be in a “Maps” folder, the .mtl file seems to recognize all of the above named Maps folders and seems to search each one until it fines the matching .jpg/.png texture/map.

Alternatively, as one of the other forum members pointed out, I could just store each “Maps” texture/map folder inside the asset of each project, but I like to keep them in Codea’s documents folder so I can reuse them for other projects.

Fyi :slight_smile:

PPS,

Sorry, @Bri_G, I just found a case where what I said above (.mtl file being able to find any texture/maps file as long as first part of folder name matched) didn’t work :frowning: . So, seems best practice to ensure .mtl file works is to make sure the texture/maps folder’s name is the same as specified in the .mtl file.

@SugarRay Here is the joystick code. I found it on the forum, but i don’t remember who wrote it.

JoyStick = class()
 
--Note all the options you can set below. Pass them through in a named table
--the damp variable sets a "dead" area in the middle of the joystick where touches don't have an effect
--the default for this is 0.1. This means that sideways or vertical movements don't have any effect until
--they get beyond 10% of the radius away from the centre. The reason is that our fingers are not accurate,
--and if you are just trying to go up, it is difficult to do that without your finger going a little left or right
--and making the plane tip as well. If the middle of the joystick is "dead", your finger doesn't need to be so
--accurate.
function JoyStick:init(t)
    t = t or {}
    self.radius = t.radius or 100  --size of joystick on screen
    self.titleDelta=self.radius*0.6
    self.stick = t.stick or 30 --size of inner circle
    self.centre = t.centre or self.radius * vec2(1,1) + vec2(5,5)
    self.damp=t.damp or vec2(0.1,0.1) --see note above
    self.position = vec2(0,0) --initial position of inner circle
    self.target = vec2(0,0) --current position of inner circle (used when we interpolate movement)
    self.value = vec2(0,0)
    self.delta = vec2(0,0)
    self.mspeed = 60
    self.moving = 0
    self.titleGlobal=""
    self.titleTop=""
    self.titleBot=""
    self.titleLeft=""
    self.titleRight=""
    self.sumy=0
    self.sumx=0
end
 
function JoyStick:draw()
--    ortho()
--    viewMatrix(matrix())
    pushStyle()
    fill(160, 182, 191, 50)
    stroke(118, 154, 195, 100)
    strokeWidth(1) 
    ellipse(self.centre.x,self.centre.y,2*self.radius)
    fill(78, 131, 153, 50)
    ellipse(self.centre.x+self.position.x, self.centre.y+self.position.y, self.stick*2)
    
    --titles
    fill(255,255,255)
    text(self.titleGlobal, self.centre.x,self.centre.y-self.radius-10)
    text(self.titleTop, self.centre.x,self.centre.y+self.titleDelta)   
    text(self.titleBot, self.centre.x,self.centre.y-self.titleDelta)  
    text(self.titleLeft, self.centre.x-self.titleDelta,self.centre.y)          
    text(self.titleRight, self.centre.x+self.titleDelta,self.centre.y)            
    popStyle()
end
 
function JoyStick:touched(t)
    if t.state == BEGAN then
        local v = vec2(t.x,t.y)
        if v:dist(self.centre)<self.radius-self.stick then
            self.touch = t.id
        end
    end
    if t.id == self.touch then
        if t.state~=ENDED then
            local v = vec2(t.x,t.y)
            if v:dist(self.centre)>self.radius-self.stick then
                v = (v - self.centre):normalize()*(self.radius - self.stick) + self.centre
            end  --set x,y values for joy based on touch
            self.target=v - self.centre
        else --reset joystick to centre when touch ends
            self.target=vec2(0,0)
            self.touch = false
        end
    end
end
 
function JoyStick:update()
    local p = self.target - self.position
    if p:len() < DeltaTime * self.mspeed then
        self.position = self.target
        if not self.touch then
            if self.moving ~= 0 then
                self.moving = self.moving - 1
            end
        else
            self.moving = 2
        end
    else
        self.position = self.position + p:normalize() * DeltaTime * self.mspeed
        self.moving = 2
    end
    local v=self.position/(self.radius - self.stick)
    return self:Dampen(v)
end

function JoyStick:Dampen(v)
    if not self.damp then return v end
    if v.x>0 then v.x=math.max(0,(v.x-self.damp.x)/(1-self.damp.x))
    else v.x=math.min(0,(v.x+self.damp.x)/(1-self.damp.x)) end
    if v.y>0 then v.y=math.max(0,(v.y-self.damp.y)/(1-self.damp.y))
    else v.y=math.min(0,(v.y+self.damp.y)/(1-self.damp.y)) end
    return v
end
 
function JoyStick:isMoving()
    return self.moving
end
 function JoyStick:isTouched()
    return self.touch
end

Thanks so much, @piinthesky, I’ll try it out! :slight_smile: