Cocea编写的一款3D地牢游戏例程

# Cocea编写的一款3D地牢游戏例程

简单介绍:就是一款用 Codea 编写的第一人称视角的 3D 迷宫游戏,你可以用你的 iPad 在这个基础上学习 3D 编程,边修改边查看效果。

这个游戏说明用 Codea 可以编出各种类型的游戏来,唯一的限制是我们的想象力!

作者:@Ignatz

原始文档链接:

http://codea.io/talk/discussion/5746/huge-3d-dungeon-updates

Git代码链接:

https://gist.github.com/dermotbalson/ae547d75672ddfbaa06e

代码中使用到的贴图资源百度网盘地址:

http://pan.baidu.com/s/1dDcSU9V

其中也包括作者关于 Codea 编程的一些电子书(简单英文):

截图:

代码:

--# Main
--Dungeon ver 1.0

--navigation
--touch left 1/3 of screen to turn left, right 1/3 of screen to turn right
--touch top 1/3 of screen to move forward, bottom 1/3 of screen to go backwards
--touch centre of screen to stop
--touching multiple times speeds up

--BUGS
--the navigation could probably be improved
--it is possible to walk through some walls (maybe my map showing which tiles are occupied, is faulty)
--also I think I have a hole in a wall somewhere

displayMode(FULLSCREEN)
supportedOrientations(LANDSCAPE_ANY)

function setup()
    FPS=60
    M=ReadMap() --see Map tab
    --set up scene
    --pass texture, texture scale (0.05 means reduce image by 95%), tile width, and wall height
    S=Scene("Dropbox:3D-walls",0.05,M.width,M.height)
    mapp={} --table which will hold the position of all the walls for collision avoidance
    for i=1,M.size.x do mapp[i]={} end --initialise
    --add walls to mesh
    --add rooms
    for i=1,#M.rooms do
        for j,w in pairs(M.rooms[i].walls) do
            S:AddSideWall(w,mapp)
        end
    end
    --add corridors
    for i=1,#M.corr do
        for j,w in pairs(M.corr[i].walls) do
            S:AddSideWall(w,mapp)
        end
    end
    --images
    --these are added differently, see Billboard class
    images={}
    for u,i in pairs(M.images) do
        images[#images+1]=Billboard(i,M.width,M.height,mapp)
    end

    --create separate "scene" for floor/ceiling because it has different texture
    F=Scene("Dropbox:3D-gravel1s",0.05,M.width,M.height)
    F:AddFloorCeiling(M.floor)

    --create map we can show on screen
    MapScale=6 --scale
    MapTrans=75 --transparency
    MapImg=image(M.size.x*MapScale,M.size.y*MapScale)
    setContext(MapImg)
    rectMode(CENTER)
    pushStyle()
    fill(255,255,255,MapTrans)
    for i=1,M.size.x do
        for j=1,M.size.y do
            if mapp[i][j]==1 then
                rect(i*MapScale,j*MapScale,MapScale,MapScale)
            end
        end
    end
    popStyle()
    setContext()

    --starting position
    --deduct 0.5 from x and z so we start in the middle of the specified tile
    --concert from tile units to pixels
    --z is made negative, if you don‘t know why, you should go read up on 3D to avoid great confusion
    pos=vec3((M.startPos.x-0.5)*M.width,M.startPos.y*M.height,-(M.startPos.z-0.5)*M.width)
    --player settings
    angle=0 --player orientation
    turnAngle=3 --how much player turns when screen is touched
    --for smoother turning, when you tap to turn, targetAngle changes, and angle will move towards it..
    targetAngle=0 --
    --..the speed with which angle changes
    angleChange=0.5
    --"tall" is the height of the camera (sorry about variable names)
    tall=M.startPos.y
    --get the light range
    range=M.range
    --set the flicker as % of total light radius
    flicker=0.3
    --this is added to current position to set the camera direction
    look=vec3(0,tall,-1000)
    lookDist=1000 --this seems to duplicate the look var, need to investigate
    --velocity
    vel=vec3(0,0,0)
    --current speed
    speed=0
    --height of the light we are holding
    lightHeight=vec3(0,M.height*0.25,0)

    --set position of map button
    mapButtonRadius=25
    mapButton=vec2(WIDTH-mapButtonRadius-5,mapButtonRadius+5)
    mapShowing=false
    --create map button
    mapButtonImg=image(mapButtonRadius*2,mapButtonRadius*2)
    setContext(mapButtonImg)
    pushStyle()
    fill(255,255,0,100)
    ellipse(mapButtonImg.width/2,mapButtonImg.height/2,mapButtonRadius*2)
    popStyle()
    setContext()

    fill(255)
    fontSize(12)
end

function draw()
    background(150)
    FPS=0.95*FPS+0.05/DeltaTime --FPS is geometric average
    perspective()
    --move towards target angle if we are turning
    if targetAngle~=angle then
        if targetAngle<angle then angle=angle-angleChange else angle=angle+angleChange end
        ChangeVel()
    end
    --camera pos
    camera(pos.x,pos.y,pos.z,pos.x+look.x,look.y,pos.z+look.z)
    --if we aren‘t walking into a wall, we can move
    if CanMove(pos+vel,mapp) then pos=pos+vel else speed=0 end
    --set flicker radius using noise
    local u=range*(1+flicker*noise(ElapsedTime))
    --draw all the walls
    S:draw(pos+lightHeight,u) --pass light position and flicker level
    --draw the floor and roof
    F:draw(pos+lightHeight,u)
    --draw billboard images (they are rotated first)
    for a,i in pairs(images) do
        i:draw(pos,u)
    end
    --draw FPS on screen
    ortho()
    viewMatrix(matrix())
    text("FPS="..math.floor(FPS),50,50)
    --draw map button
    sprite(mapButtonImg,mapButton.x,mapButton.y)
    DrawMap(pos)
end

--check if the square the player is in contains a wall
--there is a bug either in this or in my mapp table because I can
--sometimes walk through walls :(
function CanMove(v,m)
    local a=PlayerTile(v)
    if m[a.x][a.y]==1 then return false else return true end
end

function PlayerTile(v)
    return vec2(math.floor(v.x/M.width+1),math.floor(-v.z/M.width+1))
end

--handles player movement
function touched(t)
    --check for map touch first
    if t.state==BEGAN then
        if  vec2(t.x,t.y):dist(mapButton)<mapButtonRadius then
            mapShowing=not mapShowing
        elseif t.tapCount==2 then
            if t.x<WIDTH/3 then
                targetAngle=targetAngle-90
            elseif t.x>WIDTH*2/3 then
                targetAngle=targetAngle+90
            end
        else
            if t.x<WIDTH/3 then
                targetAngle=targetAngle-turnAngle
            elseif t.x>WIDTH*2/3 then
                targetAngle=targetAngle+turnAngle
            elseif t.y<HEIGHT/3 then
                speed=speed-M.walk
                ChangeVel()
            elseif t.y>HEIGHT*2/3 then
                speed=speed+M.walk
                ChangeVel()
            elseif vec2(WIDTH/2,HEIGHT/2):dist(vec2(t.x,t.y))<150 then
                speed=0
                targetAngle=angle
                ChangeVel()
            end
        end
    end
end

function DrawMap(p)
    if not mapShowing then return end
    local margin=8
    local x,y=WIDTH-MapImg.width-margin,mapButtonRadius*2+margin
    sprite(MapImg,x+MapImg.width/2,y+MapImg.height/2)
    local a=PlayerTile(p)
    pushStyle()
    fill(255,255,0,MapTrans*2)
    ellipse(x+p.x/M.width*MapScale,y-p.z/M.width*MapScale,MapScale)
    popStyle()
end

function ChangeVel()
    local a=math.rad(angle)
    local s,c=math.sin(a),math.cos(a)
    vel.x,vel.z=speed*s,-speed*c
    look.x,look.z=lookDist*s,-lookDist*c
end

--handles billboarded images
Billboard=class()

--t is table of image,x,y,z in tile units, then ambient light fraction
--w,h are map.width,map.height, m is mapp table listing all the things the player can‘t walk through
--we will add the images to this table
function Billboard:init(t,w,h,m)
    self.m=mesh()
    self.width,self.height=w,h
    m[t[2]][t[4]]=1 --mark this tie as occupied
    local tex --for image
    if type(t[1])=="string" then tex=readImage(t[1]) else tex=t[1] end
    --set position in centre of tile
    self.x,self.y,self.z=(t[2]-0.5)*self.width,t[3]*self.height,-(t[4]-0.5)*self.width
    self.angle=0 --for rotating to face the player
    self.count=0 --on;y rotate every few frames, use this counter
    --add image to mesh
    self.m:addRect(0,0,tex.width*self.y/tex.height,self.y)
    self.m.texture=tex
    --billboards have their own slightly modified shader to handle transparent pixels
    self.m.shader=shader(TransTileShader.vertexShader,TransTileShader.fragmentShader)
    self.m.shader.lightbase=t[5] --set ambient light

end

function Billboard:draw(p,r) --p is player position, r is current light range
    self.m.shader.pos=p
    self.m.shader.range=r
    --adjust rotation every 10 frames
    self.count=self.count+1
    if self.count%10==0 then
        --rotate to face player
        local dx,dz=self.x-p.x,self.z-p.z
        self.angle=math.deg(math.atan(dx/-dz))
    end
    pushMatrix()
    translate(self.x,self.y/2,self.z)
    rotate(-self.angle,0,1,0)
    self.m.shader.mModel = modelMatrix()
    self.m:draw()
    popMatrix()
end

--main class for handling map wals, floor, roof
Scene=class()

function Scene:init(tex,s,w,h) --tex is image, s is image scaling, w,h are tile size and wall height
    self.m=mesh()
    if type(tex)=="string" then tex=readImage(tex) end
    self.iw,self.ih=tex.width,tex.height
    self.width,self.height=w,h
    self.v,self.t={},{}
    self.s=s or 1
    self.m.texture=tex
    self.m.shader=shader(TileShader.vertexShader,TileShader.fragmentShader)
end

--v1,v2,v3,v4 are positions of the four wall corners
function Scene:AddWall(v1,v2,v3,v4)
    --figure out tex coords, ie which way the wall is pointing
    local d=v2-v1
    local dx,dy
    if d.x~=0 then dx=d.x elseif d.y~=0 then dx=d.y else dx=d.z end
    d=v3-v2
    if d.x~=0 then dy=d.x elseif d.y~=0 then dy=d.y else dy=d.z end
    --next bit is important for tiling, calculate texture upper limit as width of mesh / size of scaled image
    local tx1,tx2=0,math.abs(dx)/self.iw/self.s
    local ty1,ty2=0,math.abs(dy)/self.ih/self.s
    --vertices
    local n=#self.v
    self.v[n+1],self.v[n+2],self.v[n+3],self.v[n+4],self.v[n+5],self.v[n+6]=v1,v2,v3,v3,v4,v1
    --add to existing mesh vertices which are stored in a "buffer"
    local b=self.m:buffer("position")
    b:resize(n+6)
    for i=1,#self.v do b[i]=self.v[i] end
    --now the texture mappings
    local n=#self.t
    self.t[n+1],self.t[n+2],self.t[n+3],self.t[n+4],self.t[n+5],self.t[n+6]=
        vec2(tx1,ty1),vec2(tx2,ty1),vec2(tx2,ty2),vec2(tx2,ty2),vec2(tx1,ty2),vec2(tx1,ty1)
    --add to texture buffer
    local b=self.m:buffer("texCoord")
    b:resize(n+6)
    for i=1,#self.t do b[i]=self.t[i] end
    self.m:setColors(color(255))
end

--calculates corner vecs for a wall, given a vec4 containing (x1,z1,x2,z2)
function Scene:AddSideWall(v,m) --m is mapp table listing tiles containing walls
    local x1,y1,z1=(v.x-0.5)*self.width,0,-(v.y-0.5)*self.width
    local x2,y2,z2=(v.z-0.5)*self.width,self.height,-(v.w-0.5)*self.width
    self:AddWall(vec3(x1,y1,z1),vec3(x2,y1,z2),vec3(x2,y2,z2),vec3(x1,y2,z1))
    --update mapp table to show these tiles are occupied
    if m then
        for i=math.min(v.x,v.z),math.max(v.x,v.z) do
            m[i][v.y]=1
        end
        for i=math.min(v.y,v.w),math.max(v.y,v.w) do
            m[v.x][i]=1
        end
    end
end

--simpified version of AddSideWall, only this wall is horizontal
function Scene:AddFloorCeiling(v)
    local x1,z1=(v.x-0.5)*self.width,-(v.y-0.5)*self.width
    local x2,z2=(v.z-0.5)*self.width,-(v.w-0.5)*self.width
    self:AddWall(vec3(x1,0,z1),vec3(x2,0,z1),vec3(x2,0,z2),vec3(x1,0,z2))
    self:AddWall(vec3(x1,self.height,z1),vec3(x2,self.height,z1),vec3(x2,self.height,z2),vec3(x1,self.height,z2))
end

--not used
function Scene:AddLight(v)
    self.m.shader.light=vec3(v.x*self.width,v.y*self.height,v.z*self.width)
end

function Scene:draw(p,r)
    self.m.shader.pos=p
    self.m.shader.range=r
    self.m.shader.mModel = modelMatrix()
    self.m:draw()
end

--this shader used by the walls, floor, roof
TileShader = {
vertexShader = [[
uniform mat4 modelViewProjection;
uniform mat4 mModel;
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying highp vec4 vPosition;

void main()
{
    vColor = color;
    vTexCoord = texCoord;
    gl_Position = modelViewProjection * position;
    vPosition = mModel * position; //needed to set light intensity
}

]],
fragmentShader = [[
precision highp float;
uniform lowp sampler2D texture;
uniform lowp float range;  //light range
uniform lowp vec3 pos;  //position of player
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying highp vec4 vPosition; //position of current pixel         

void main()
{
    float f=max(0.,1.0-length( pos - vPosition.xyz ) / range); //light reduces linearly with distance
    //next is the magic line of code that tiles the image across areas of any size
    //it is multiplied by the light intensity calculated above
    lowp vec4 col = f*texture2D( texture, vec2(mod(vTexCoord.x,1.0), mod(vTexCoord.y,1.0)));
    col.a=1.0;
    gl_FragColor =col;
}
]]
}

--this shader is used by the images
--the only difference is that transparent pixes are discarded
TransTileShader = {
vertexShader = [[
uniform mat4 modelViewProjection;
uniform mat4 mModel;
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying highp vec4 vPosition;

void main()
{
    vColor = color;
    vTexCoord = texCoord;
    gl_Position = modelViewProjection * position;
    vPosition = mModel * position;
}

]],
fragmentShader = [[
precision highp float;
uniform lowp sampler2D texture;
uniform lowp float range;
uniform lowp float lightbase;
uniform lowp vec3 pos;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
varying highp vec4 vPosition;          

void main()
{
    lowp vec4 col = texture2D( texture, vTexCoord );
    if (col.a==0.0) discard; //this is the only difference
    else {
    //lightbase below is the ambient light of this object, gives it a glow if you want one
    float f=max(0.,1.0-length( pos - vPosition.xyz ) / range)+lightbase;
    col = col*f;
    col.a=1.0;
    gl_FragColor=col;
    }
}
]]
}
--# Map
--Dungeon map

--this map is organised as a table
--the map is a rectangular grid of squares
--image here: http://i1303.photobucket.com/albums/ag142/ignatz_mouse/dungeon_zpsc89352fc.png

--Thinking I would have to cull (ie ony draw stuff directly around the player), I organised the map
--to have corridors between all the rooms. This made it easier to say "if you are in room X, also draw
--corridors "Y and Z". It proved unnecessary - so far.
--anyway, that is why I have organised the walls by room, and separatey for rooms and corridors

--LOCATION OF IMAGES REQUIRED
--https://www.dropbox.com/sh/i7stxdfcnnh8azx/AAByAiTG7oswE7nczwZj4pxUa?dl=0

function ReadMap()
    local map={}
    map.width=10  --number of pixels per square (not a good variable name!)
    map.height=20 --height of walls in pixels
    map.size=vec2(82,114) --number of tiles wide and deep
    map.startPos=vec3(72,0.5,8) --starting tile
    map.walk=0.2  --speed change (pixels/sec) when you touch screen
    map.range=100 --range of light, in pixels
    map.rooms,map.corr={},{} --rooms and corridors stored separately
    --load the map coordinates
    local m,c=map.rooms,map.corr
    for i=1,23 do m[i]={} end
    for i=1,30 do c[i]={} end
    --the rooms and corr tables have provision for wall and neighbour settings
    --I‘m only using wall settings, as explained above

    --room 1
    --each wall is stored in a vec4 = (x1,z1,x2,z2) in tile units
    --no need for a y value, we know each wall goes from 0 to map.height
    m[1].walls={vec4(64,11,75,11),vec4(75,11,75,4),vec4(61,4,75,4),vec4(61,10,61,4)}
    --m[1].neighbours={m.corr1}	--this was where I was going to specify neighbours
    m[2].walls={vec4(41,10,56,10),vec4(56,13,56,10),
            vec4(40,19,40,13),vec4(40,19,53,19),vec4(56,19,56,16)}
    m[3].walls={vec4(21,16,21,1),vec4(21,1,30,1),vec4(30,10,30,1),vec4(30,20,30,13),
                    vec4(21,20,30,20),vec4(21,20,21,19)}
    m[4].walls={vec4(32,21,34,21),vec4(32,27,32,21),vec4(32,36,32,30),
                    vec4(38,21,40,21),vec4(40,24,40,21),vec4(40,36,40,27),vec4(35,36,40,36)}
    m[5].walls={vec4(13,33,13,21),vec4(16,21,22,21),vec4(22,27,22,21),
                vec4(22,39,22,30),vec4(13,39,22,39),vec4(13,39,13,36)}
    m[6].walls={vec4(8,28,11,28),vec4(11,28,11,21),vec4(5,21,11,21),vec4(5,28,5,21),vec4(5,28,6,28)}
    m[7].walls={vec4(2,39,2,30),vec4(2,30,6,30),vec4(8,30,11,30),
                vec4(11,33,11,30),vec4(11,39,11,36),vec4(2,39,11,39)}
    m[8].walls={vec4(50,39,50,30),vec4(50,30,59,30),vec4(59,45,59,30),
                vec4(50,45,59,45),vec4(50,45,50,42)}
    m[9].walls={vec4(23,48,23,47),vec4(23,48,29,48),vec4(32,48,37,48),
        vec4(37,48,37,41),vec4(35,41,37,41),vec4(23,41,32,41),vec4(23,44,23,41)}
    m[10].walls={vec4(10,56,16,56),vec4(10,56,10,41),vec4(10,41,19,41),vec4(19,44,19,41),vec4(19,56,19,47)}
    m[11].walls={vec4(34,68,34,62),vec4(34,68,39,68),vec4(34,59,34,52),
                vec4(34,52,48,52),vec4(48,59,48,52),vec4(48,68,48,62),vec4(43,68,48,68)}
    m[12].walls={vec4(61,56,61,50),vec4(61,56,66,56),vec4(69,56,72,56),
                vec4(72,56,72,41),vec4(67,41,72,41),vec4(61,41,64,41),vec4(61,47,61,41)}
    m[13].walls={vec4(13,85,19,85),vec4(13,85,13,76),vec4(13,76,16,76),
                vec4(19,76,27,76),vec4(27,85,27,76),vec4(21,85,27,85)}
    m[14].walls={vec4(29,91,29,81),vec4(29,81,32,81),vec4(35,81,39,81),
                vec4(43,81,45,81),vec4(45,87,45,81),vec4(37,91,45,91),vec4(29,91,34,91)}
    m[15].walls={vec4(50,93,50,91),vec4(50,93,58,93),vec4(50,87,50,84),vec4(50,84,55,84),vec4(59,90,59,84)}
    m[16].walls={vec4(50,76,50,64),vec4(50,64,61,64),vec4(61,70,61,64),
            vec4(61,79,61,73),vec4(59,79,61,79),vec4(51,79,55,79)}
    m[17].walls={vec4(74,99,74,93),vec4(74,99,82,99),vec4(82,99,82,84),vec4(74,84,82,84),vec4(74,90,74,84)}
    m[18].walls={vec4(50,105,50,99),vec4(50,105,59,105),vec4(59,105,59,96),vec4(51,96,59,96)}
    m[19].walls={vec4(28,114,28,107),vec4(28,107,34,107),vec4(28,114,34,114),
            vec4(34,114,34,110),vec4(34,108,34,107)}
    m[20].walls={vec4(36,111,36,110),vec4(36,111,48,111),vec4(48,111,48,101),
            vec4(45,101,48,101),vec4(36,101,42,101),vec4(36,108,36,101)}
    m[21].walls={vec4(63,114,63,104),vec4(63,114,77,114),vec4(77,114,77,104),
    vec4(69,104,77,104),vec4(63,104,66,104)}
    m[22].walls={vec4(23,69,23,65),vec4(23,69,27,69),vec4(29,69,30,69),
            vec4(30,69,30,65),vec4(26,65,30,65),vec4(23,65,24,65)}
    m[23].walls={vec4(21,63,24,63),vec4(26,63,27,63),vec4(27,63,27,58),vec4(21,58,27,58),vec4(21,60,21,58)}

    --corridors now
    c[1].walls={vec4(56,13,61, 13),vec4(61,13,61, 10),vec4(56,16,64, 16),vec4(64,16,64, 11)}
    c[2].walls={vec4(38,13,40, 13),vec4(38,21,38, 13),vec4(34,21,34, 13),
                        vec4(30,13,34, 13),vec4(30,10,41, 10)}
    c[3].walls={vec4(16,19,21,19),vec4(16,21,16,19),vec4(13,16,21,16),vec4(13,21,13,16)}
    c[4].walls={vec4(53,24,53,19),vec4(56,24,56,19),vec4(40,24,53,24),
                vec4(56,24,67,24),vec4(40,27,64,27),vec4(64,41,64,27),vec4(67,41,67,24)}
    c[5].walls={vec4(8,30,8,28),vec4(6,30,6,28)}
    c[6].walls={vec4(22,27,32,27),vec4(22,30,32,30)}
    c[7].walls={vec4(32,41,32,36),vec4(35,41,35,36)}
    c[8].walls={vec4(19,47,23,47),vec4(19,44,23,44)}
    c[9].walls={vec4(29,62,29,48),vec4(32,59,32,48),vec4(29,62,34,62),vec4(32,59,34,59)}
    c[10].walls={vec4(48,59,53,59),vec4(48,62,56,62),vec4(56,62,56,50),
            vec4(53,59,53,50),vec4(56,50,61,50),vec4(45,50,53,50),vec4(45,50,45,39),
        vec4(45,39,50,39),vec4(48,42,50,42),vec4(48,47,48,42),vec4(48,47,61,47)}
    c[11].walls={vec4(66,70,66,56),vec4(69,77,69,56),vec4(66,77,66,73),vec4(61,73,66,73),vec4(61,70,66,70)}
    c[12].walls={vec4(66,90,66,78),vec4(69,90,69,79)}
    c[13].walls={vec4(69,93,74,93),vec4(69,90,74,90)}
    c[14].walls={vec4(58,93,66,93),vec4(59,90,66,90)}
    c[15].walls={vec4(45,91,50,91),vec4(45,87,50,87)}
    c[16].walls={vec4(19,88,19,85),vec4(21,88,21,85)}
    c[17].walls={vec4(43,79,51,79),vec4(43,76,50,76)}
    c[18].walls={vec4(16,76,16,56),vec4(19,60,19,56),vec4(19,70,19,63),vec4(19,76,19,73)}
    c[19].walls={vec4(19,63,21,63),vec4(19,60,21,60)}
    c[20].walls={vec4(19,73,32,73),vec4(19,70,27,70),vec4(29,70,35,70),vec4(35,81,35,70),vec4(32,81,32,73)}
    c[21].walls={vec4(39,81,39,68),vec4(43,81,43,79),vec4(43,76,43,68)}
    c[22].walls={vec4(34,99,34,91),vec4(34,99,42,99),vec4(37,96,50,96),vec4(45,99,50,99),vec4(37,96,42,96)}
    c[23].walls={vec4(42,101,42,99),vec4(45,101,45,99)}
    c[24].walls={vec4(34,110,36,110),vec4(34,108,36,108)}
    c[25].walls={vec4(66,104,66,93),vec4(69,104,69,93)}
    c[26].walls={vec4(55,84,55,79),vec4(59,84,59,79)}
    c[27].walls={vec4(69,79,72,79),vec4(69,77,72,77)}
    c[28].walls={vec4(24,65,24,63),vec4(26,65,26,63)}
    c[29].walls={vec4(11,36,13,36),vec4(11,33,13,33)}
    c[30].walls={vec4(27,70,27,69),vec4(29,70,29,69)}
    --floor coords, wil be used for roof too
    map.floor=vec4(2,1,82,114)
    --set of images to be billboarded
    --table contains image, x, y, z, s
    --where x,z are tile positions, y is fraction of map.height
    --and s is ambient lighting, 0 for none, 1 for bright, this property makes them glow in the dark
    map.images={
        {readImage("Dropbox:Gargoyle"),53,0.5,16,0.2},
        {readImage("Dropbox:Gargoyle"),53,0.5,14,0.2},
        {readImage("Dropbox:Buddha1"),34,0.5,23,0.2},
        {readImage("Dropbox:Buddha2"),36,0.5,11,0.4}
        }

    return map
end
时间: 2024-10-09 22:06:27

Cocea编写的一款3D地牢游戏例程的相关文章

制作一款3D炸弹超人游戏

说起炸弹超人,相信很多朋友都玩过类似的游戏,其中最为人熟知的莫过于<泡泡堂>.该类型游戏需要玩家在地图中一边跑动一边放置炸弹,同时还要躲避敌方炸弹保护自己.最初的炸弹超人游戏都是2D的,今天这篇文章将教大家在Unity中实现一款3D的炸弹超人游戏. 准备工作 将项目初始资源导入Unity项目,资源目录如下: 其中分别包含要用于游戏的动画.材质.模型.背景音乐.物理材质.预制件.场景.脚本.音效及图片资源. 放置炸弹 打开项目中的Game场景并运行. 可以通过WASD键或方向键来操作所有角色进行

MyGame--java语言编写的一款打飞机游戏

运行效果如下图所示: 点击这里进行下载, 还有源码已经传至我的github上,还有一些小bug,欢迎大家改正. 说明:最后打boss的效果还没做,爆炸的图片也没好,欢迎大家修改.

张瀚荣:如何用UE4制作3D动作游戏

转自:http://www.gamelook.com.cn/2015/06/218267 GameLook报道/ 6月5日,2015年第三期GameLook开放日?虚幻引擎专场活动在上海正式举行,此次活动由Epic Games与GameLook联合主办. 动作游戏凭借爽快的打击感和强烈的操作感一直受到玩家的喜爱,但一些高品质的3D动作游戏设计其实颇有难度,国内市场上常见的大多是横版2D游戏.本次活动上,Megafun的创始人张瀚荣来分享了利用UE4引擎制作3D横版动作游戏的心得. 张瀚荣从策划的

40款免费开源游戏

开源游戏最大的特点的免费,所以我们玩的开源游戏都是正版游戏,另外开源游戏对外开 放源代码,任何有兴趣的人可以对其改进,其游戏的可玩性,易玩性都会逐步提高,也可以说开源游戏融合了众人智慧,是网友分享的成果.这里搜集了 40款免费开源游戏 ,全部是 WINDOWS版本,喜欢玩游戏的朋友不要错过. 冒险—角色扮演游戏 1.Daimonin 这是一块免费的奇幻网游,总体看游戏在2D MMORPG游戏圈以及低配置游戏圈内是一个不错的选择.玩家在游戏中可体现到不同的游戏经历和开发商独特的游戏设计理念.游戏中

Android 八款开源 Android 游戏引擎

原文地址 本文内容 Angle Rokon LGame AndEngine libgdx jPCT Alien3d Catcake 最近无意间看到一篇关于 Android 搜索引擎的文章,于是搜索了,学不学是其次,主要是要有这方面的知识--技多不压身嘛~ 下面罗列出八款常见的 Android 游戏引擎,以供参考.收费.下载量过小.不公开源码,以及鄙人不知道(-_-)的引擎不在此列. Angle Angle 是一款专为 Android 平台设计的,适合快速开发的 2D 游戏引擎,基于 OpenGL

[Android游戏开发]八款开源 Android 游戏引擎 (巨好的资源)

初学Android游戏开发的朋友,往往会显得有些无所适从,他们常常不知道该从何处入手,每当遇到自己无法解决的难题时,又往往会一边羡慕于 iPhone下有诸如Cocos2d-iphone之类的免费游戏引擎可供使用,一边自暴自弃的抱怨Android平台游戏开发难度太高,又连个像样的游 戏引擎也没有,甚至误以为使用Java语言开发游戏是一件费力不讨好且没有出路的事情. 事实上,这种想法完全是没有必要且不符合实际的,作为能和苹果iOS分庭抗礼的Android(各种意义上),当然也会有相当数量的游戏引擎存

3D飞镖游戏源码ios版

一款ios 3D飞镖游戏源码,通过物理引擎和重力感应来控制飞镖向目标物体击中!游戏比较简单,可以学习一下3D游戏的基本开发. 源码下载: http://code.662p.com/view/6262.html 开发平台: 在xcode 4.3编译通过,iphone4(ios5.1)完美运行 截图: <ignore_js_op> <ignore_js_op> 详细说明:http://ios.662p.com/thread-1427-1-1.html  

一款开源的游戏服务端引擎KBEngine

什么是KBEngine? 一款开源的游戏服务端引擎,使用简单的约定协议就能够使客户端与服务端进行交互,使用KBEngine插件能够快速与(Unity3D, OGRE, Cocos2d-x, HTML5, 等等)技术结合形成一个完整的客户端. 服务端底层框架使用C++编写,游戏逻辑层使用Python(支持热更新),开发者无需重复的实现一些游戏服务端通用的底层技术,将精力真正集中到游戏开发层面上来,快速的打造各种网络游戏. (经常被问到承载上限,kbengine底层架构被设计为多进程分布式动态负载均

基于html5制作3D拳击游戏源码下载

今天给大家分享一款基于HTML5实现的3d拳王游戏源码.这款实例适用浏览器:360.FireFox.Chrome.Safari.Opera.傲游.搜狗.世界之窗. 不支持IE8及以下浏览器. 在线预览   源码下载 实现的代码. html代码: <div id="chf2" style="position: relative; width: 320px; margin: 0 auto;"> <canvas id="gcvs" w