vec2 for terrain.

Hi again guys! I have been trying to make 2d terrain for my game, made out of vec2s and sprites, it seems as if I’m doing something wrong though.
Code:

-- Char

function setup()
    print("Hello World!")
    char = vec2(100,200)
    charW = 10
    charH = 75
    touchx = 0
    hurt = false
    blocks1 = {}
    x = 20
    for i=1, 60 do
    table.insert(blocks1, vec2(x, math.random(1, 13)))
    x = x + 20
    jump = false
    fall = true
    end
      
end


function draw()
   if fall == true then
    char.y = char.y - 1
    end
    background(19, 19, 19, 255)
    xChar:draw()
    
-- WIP code for character 
   if touchx > char.x then
        char.x = char.x + 1
        charW = -10*3
        end
        
if touchx < char.x then 
    char.x = char.x - 1
    charW = 10*3
    end    
    -- This sets the line thickness
    strokeWidth(5)
--for b=1, #blocks1 do
   --tint(47, 36, 30, 255)
    --sprite("Documents:Star", blocks1[b].x, blocks1[b].y, 20, 200)
     
    --end
    -- Do your drawing here
  for i, v in ipairs(blocks1) do
    
    
    v.y = blocks1[i].y
    v.x = blocks1[i].x
    
      sprite("Documents:Star", blocks1[i].x, blocks1[i].y, 20, 200)
    
     if --math.abs(blocks1[i].x - char.x)<charH/2 --and 
     math.abs(v.y - char.y)< charH/2 
then fall = false 
        else
        fall = true
        end
            
  
    
    end
    
end

function touched(touch)
    touchx = touch.x
 
  
    end

@Prynok - please put the first three ~ on a separate line, the formatting is messed up

Please also tell us what the problem is

Sorry, the problem is that the character still just falls through the terrain.

  -- Char

function setup() print("Hello World!") char = vec2(100,200) charW = 10 charH = 75 touchx = 0 hurt = false blocks1 = {} x = 20 for i=1, 60 do table.insert(blocks1, vec2(x, math.random(1, 13))) x = x + 20 jump = false fall = true end

end

function draw() if fall == true then char.y = char.y - 1 end background(19, 19, 19, 255) xChar:draw()

-- WIP code for character if touchx > char.x then char.x = char.x + 1 charW = -10*3 end

if touchx < char.x then char.x = char.x - 1 charW = 10*3 end
-- This sets the line thickness strokeWidth(5) --for b=1, #blocks1 do --tint(47, 36, 30, 255) --sprite("Documents:Star", blocks1[b].x, blocks1[b].y, 20, 200)

--end
-- Do your drawing here
for i, v in ipairs(blocks1) do

v.y = blocks1[i].y
v.x = blocks1[i].x

  sprite("Documents:Star", blocks1[i].x, blocks1[i].y, 20, 200)

 if --math.abs(blocks1[i].x - char.x)<charH/2 --and 
 math.abs(v.y - char.y)< charH/2 
then fall = false else fall = true end

end
end

function touched(touch) touchx = touch.x

end

Is this possible? Or should I try a different method.

I think that if statement you have is goofy.

First off, if you are going to remove the commented stuff, remove it from this post.

Second, you seem to be comparing the position of the ground minus the character position and seeing if the result is less that half the character height. Personally, I’d do that math on a separate line and I’d actually split it into two, then compare the results, easier to debug.

What I don’t understand is why you are checking half the char’s height - it look like you have blocks at cords with no height, so why does the character need height for the check?

Yeah, this whole piece seems dodgy…

if --math.abs(blocks1[i].x - char.x)<charH/2 --and 
 math.abs(v.y - char.y)< charH/2 
then fall = false else fall = true end

first, (v.y-char.y) is backward. Codea places the origin (0,0) at the bottom-left corner of the screen. So when char is above the ground, the y value will always be greater than the ground height.

second, it makes more sense to compare your character’s altitude against the ground height. The comparison you’re doing there doesn’t make any sense until the reader rips it apart and use some algebra to figure out what you’re actually trying to do.

Try this, instead:


if (char.y+charH/2) > v.y) then
    fall=true
else
    fall=false
end

As rule, I never use an if/then statement when all you’re doing is setting a Boolean value true or false. Instead, just assign the comparison directly to the Boolean.


fall = (char.y+charH/2) > v.y

Finally, you could consider changing your sprite drawing to use CORNER. That simplifies your routine even more, since the x,y positions specified in the Sprite function indicate the lower-left corner of the sprite, not the center.


-- at the top of draw()
rectMode(CORNER)

-- in  your collision testing loop
fall=char.y > v.y

Yeah, I guess I was a bit to tired when I was making this code, but it still doesn’t work. I think the problem is it doesn’t know what block is under the character, is that possible?

That’s your job as a programmer. You have to determine whether the space you’re about to move your character to is already occupied. Then you have to decide what to do when you get there.

The simplest possible method would be a world set up in a square grid, like a chess board. You just test the squares your character could be touching after the next movement cycle…

It’s up to you to decide which blocks are close enough to touch. The usual way is to arrange your blocks in a grid, then store the grid in an array (lua calls them “tables”.)

The simplest way to store your world in a packed array.

To create your initial map, you create a table with width*height elements and set each element to an “air” block, so that something gets drawn on the screen in that space. The bottom row gets set to “solid” blocks.

function createMap(cols,rows,airBlock,solidBlock)
    map = {}  -- map is a global
    mapRows=rows
    mapCols=cols

    local x
    local y
    for x=1,mapRows do
        for y=1,mapCols do
            if y == 1 then
                map[x*mapRows+y]=solidBlock
            else
                map[x*mapRows+y]=airBlock
            end
        end
    end
end

to find a spot on the grid, you do this:

gridX=math.floor(char.x/gridSize)
gridY=math.floor(char.y/gridSize)

to get an individual block from your map, you can use the maths. calling getBlock(48,12) would return the block in column 2, row 1

function getBlock(x,y)
    gridX=math.floor(char.x/gridSize)
    gridY=math.floor(char.y/gridSize)

    return map[gridX*mapCols+y]
end function

so to find out if the cell below your character is occupied with a solidBlock, do this:

--this example assumes spriteMode(CORNER)
if getBlock(charX,charY-1)==solidBlock 
  or getBlock(charX+gridSize-1,charY-1)==solidBlock then
    fall=false
end

You should actually test two spots: the character’s bottom-left corner and its bottom-right corner. that’s what the second part of that if statement is doing; it’s checking the bottom-right corner.

Now this all assumes that your character falls at a speed of less than one gridSize per frame. Normally, that’s not a problem, but you will want to clamp your maximum velocity, just to make sure.

@tomxp411 (*)

But how could you make this into random terrian, sorry trying to process this in my nooby brain

Do you mean “random terrain” as in, stuff is just scattered around, or random as in “arbitrary”, ie: terrain you design.

either way, you need a setBlock function, like this:

-- place block in a grid square
-- (0,0) is lower-left corner of grid
function setBlock(gridX,gridY,block)
    map[gridx*gridSize+y]=block
end

Based on the kinds of questions you’re asking, I take it you’re new to programming?

(just ignore the dupe posts. the board kept returning an error, so I didn’t realize I was actually posting successfully…)

xx

x

Thank you, and no I’m not new to programming, just new to lua and codea :slight_smile:

We all start off as Codea noobs :wink: