Simple isometric clicky game engine. Work in progress.
A Pen by Eric Brewer on CodePen.
body | |
#wrapper | |
#game |
Simple isometric clicky game engine. Work in progress.
A Pen by Eric Brewer on CodePen.
### | |
~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ | |
~ Main game class | |
~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ | |
### | |
class Game | |
constructor:(@container, @tileSize, {viewWidth, viewHeight, scale, iso} = {}) -> | |
viewWidth ?= 600 | |
viewHeight ?= 400 | |
scale ?= 1 | |
iso ?= false | |
@viewWidth = viewWidth | |
@viewHeight = viewHeight | |
@scale = scale | |
@iso = iso | |
run: -> | |
@setup() | |
@then = Date.now() | |
setInterval @tick, 30 | |
setup: -> | |
@world = new World @container, @tileSize, @viewWidth, @viewHeight, @scale, @iso | |
@inputHandler = new InputHandler( @world ) | |
update:(modifier) -> | |
@inputHandler.update(modifier) | |
@world.update() | |
tick: => | |
now = Date.now() | |
delta = now - @lastUpdate | |
@lastUpdate = now | |
@lastElapsed = delta | |
@update(delta / 1000) | |
@world.draw() | |
### | |
~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ | |
~The World Class | |
~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ | |
### | |
class World | |
constructor: (@container, tileSize, @viewWidth, @viewHeight, @scale, @iso) -> | |
@debug = false | |
@tileWidth = if @iso then tileSize * 2 * @scale else tileSize * @scale | |
@tileHeight = tileSize * @scale | |
@ctx = @createCanvas() | |
@sprites = [] | |
@scrollX = 0 | |
@scrollY = 0 | |
createCanvas: -> | |
container = document.getElementById @container | |
canvas = document.createElement('canvas') | |
canvas.setAttribute('id', 'eNgine_canvas') | |
canvas.width = @viewWidth | |
canvas.height = @viewHeight | |
container.appendChild canvas | |
@canvas = canvas | |
@canvas.getContext('2d') | |
createWorld: (@map) -> | |
### | |
create a collision map based on the map | |
switch all unwalkable tiles to 1s on cmap | |
for pathfinding | |
### | |
@cMap = @map | |
for row in @cMap | |
for tile in row | |
if row[tile] is not 0 | |
row[tile] = 1 | |
@createBackground( @map ) | |
@createPFGrid( @cMap ) | |
createBackground: (map) => | |
@background = new Background this, map | |
createPFGrid: (cMap )-> | |
@grid = new PF.Grid( cMap[0].length, cMap.length, cMap) | |
#@finder = new PF.AStarFinder() | |
@finder = new PF.BreadthFirstFinder() | |
update: (modifier) -> | |
sprite.update() for sprite in @sprites | |
draw: -> | |
@ctx.clearRect 0, 0, @viewWidth, @viewHeight | |
sprite.draw() for sprite in @sprites | |
### | |
~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ | |
~The Input Handler Class | |
~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ | |
### | |
class InputHandler | |
keysDown : {} | |
clicked: false | |
constructor: (@world) -> | |
@bindMouse() | |
bindMouse: => | |
that = this | |
@world.canvas.addEventListener('mousemove', (evt)-> | |
that.mousePos = that.getMousePos(evt) | |
) | |
getMousePos:(evt) -> | |
rect = @world.canvas.getBoundingClientRect() | |
{ x: evt.clientX - rect.left, y: evt.clientY - rect.top } | |
update: (modifier) -> | |
### | |
clear previous flags | |
### | |
for i in [0 .. @world.background.tiles.length] | |
if @world.background.tiles[i] | |
@world.background.tiles[i].clearFlags 'hover' | |
### | |
main input update | |
### | |
if @world.background and @world.background.ready and @mousePos and @mousePos.x > 0 and @mousePos.x < @world.viewWidth and @mousePos.y > 0 and @mousePos.y < @world.viewHeight | |
if @world.iso | |
tileX = Math.floor ( (@mousePos.x + @world.scrollX) / @world.tileWidth ) + ( (@mousePos.y + @world.scrollY) / @world.tileHeight) - .5 | |
tileY = Math.floor ( (@mousePos.y + @world.scrollY) / @world.tileHeight ) - ( (@mousePos.x + @world.scrollX) / @world.tileWidth) + .5 | |
else | |
tileX = Math.floor (@mousePos.x + @world.scrollX) / @world.tileWidth | |
tileY = Math.floor (@mousePos.y + @world.scrollY) / @world.tileHeight | |
if @world.background.mapTiles[tileY] | |
if @world.background.mapTiles[tileY][tileX] | |
theTile = @world.background.mapTiles[tileY][tileX] | |
if theTile.walkable | |
theTile.setFlags('hover') | |
if @clicked | |
for tile in @world.background.tiles | |
tile.clearFlags 'selected' | |
tile.clearFlags 'path' | |
#if @world.player.path | |
#for tile in @world.player.path | |
#@world.background.mapTiles[tile[1]][tile[0]].clearFlags 'path' | |
theTile.setFlags 'selected' | |
### | |
Pathfinding | |
### | |
pcoords = @world.player.getTile() | |
goalX = theTile.rX | |
goalY = theTile.rY | |
gridClone = @clone @world.grid | |
path = @world.finder.findPath pcoords.x, pcoords.y, tileX, tileY, gridClone | |
for tile in path | |
@world.background.mapTiles[tile[1]][tile[0]].setFlags 'path' | |
@world.background.mapTiles[ path[0][1] ][path[0][0]].clearFlags 'path' | |
@world.player.walkPath path | |
### | |
clear click | |
### | |
@clicked = false | |
clone: (obj) -> | |
if not obj? or typeof obj isnt 'object' | |
return obj | |
if obj instanceof Date | |
return new Date(obj.getTime()) | |
if obj instanceof RegExp | |
flags = '' | |
flags += 'g' if obj.global? | |
flags += 'i' if obj.ignoreCase? | |
flags += 'm' if obj.multiline? | |
flags += 'y' if obj.sticky? | |
return new RegExp(obj.source, flags) | |
newInstance = new obj.constructor() | |
for key of obj | |
newInstance[key] = @clone obj[key] | |
newInstance | |
### | |
~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ | |
~The Sprite Class | |
~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ | |
### | |
class SpriteImage | |
ready: false | |
constructor:(@url = 'images/spritesheet.png', world, sprite) -> | |
image = new Image | |
#image = document.createElement('img') | |
image.src = @url | |
@image = image | |
@image.onload= => | |
@ready = true | |
#if world.debug | |
#console.log 'created a ' + sprite | |
class Sprite | |
x: 0 #world-relative x | |
y: 0 #world-relative y | |
w: 0 | |
h: 0 | |
name: 'sprite' | |
collides: false | |
ready: false | |
image: false | |
@animationFrames = 1 | |
constructor: (@world, url) -> | |
if url | |
@image = new SpriteImage url, @world, @name | |
console.log @world if @world.debug | |
@rX = @x | |
@rY = @y | |
@world.sprites.push this | |
setAnimationFrames: (frames) -> | |
@animationFrames = frames | |
update: (modifier) -> | |
@rX = @x + @world.scrollX | |
@rY = @y + @world.scrollY | |
draw: -> | |
if @image.ready | |
sx = ( @w * @frame ) | |
sy = 0 | |
@world.ctx.drawImage( @image.image, sx, sy, @w, @h, @rX , @rY , @w, @h ) | |
drawFrame: (frame) -> | |
sx = 0 - ( @w * frame ) | |
sy = 0 | |
@world.ctx.drawImage( @image, sx, sy, @rX, @rY, @w, @h ) | |
### | |
~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ | |
~The Background Class | |
~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ | |
### | |
class Background extends Sprite | |
constructor: (@world, map) -> | |
@x = 0 | |
@y = 0 | |
@w = 0 | |
@h= 0 | |
@rX = @x | |
@rY = @y | |
@tiles = [] | |
@mapTiles =[] | |
@map = map | |
for rIndex, row of @map | |
@mapTiles[rIndex] = [] | |
#TODO go backwards to render in sequence | |
for i in [row.length-1..0] by -1 | |
cIndex = i | |
column = row[cIndex] | |
w= @world.tileWidth | |
h= @world.tileHeight | |
x = cIndex | |
y = rIndex | |
tileNo = [cIndex, rIndex] | |
walkable = true | |
if column != 0 then walkable = false | |
if @world.iso | |
isoCoords = @twoDToIso x, y, w, h | |
tile = new DrawnTile @world, isoCoords.x, isoCoords.y, @world.tileWidth, @world.tileHeight, column, tileNo, walkable | |
else | |
x = cIndex * w | |
y = rIndex * h | |
tile = new Tile @world, x, y, @world.tileWidth, @world.tileHeight, 'tile', tileNo, walkable | |
@tiles.push tile | |
@mapTiles[rIndex][cIndex] = tile | |
@ready = true | |
console.log @tiles if @world.debug | |
twoDToIso: (x, y, w, h)-> | |
isoX = (x * w / 2) - (y * w / 2) | |
isoY = (y * h / 2) + (x * h / 2) | |
{x: isoX, y: isoY} | |
backgroundSize: -> | |
update: (modifier) -> | |
super | |
### | |
~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ | |
~The Tile Class | |
~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ | |
### | |
class Tile extends Sprite | |
constructor: (@world, @x, @y, @w, @h, @type = 0, @tileNo = [0, 0], @walkable=true)-> | |
@name = 'tile' | |
image = @getType() | |
@color = 'rgba(0,0,255,' + (parseInt(@tileNo[0]) / 10) + ')' | |
@flags = {} | |
@tileFrame = @getTileFrame() | |
super @world, image | |
update: (modifier)-> | |
@rX = @x - @world.scrollX | |
@rY = @y - @world.scrollY | |
### | |
different tiles | |
### | |
@frame = @tileFrame | |
if @flags.hover | |
@frame = 1 | |
if @flags.selected | |
@frame = 2 | |
if @flags.path | |
@frame = 3 | |
draw: (frame = 0)-> | |
#@world.ctx.fillStyle = '#d6abb1' | |
#@world.ctx.fillRect @x, @y, @w, @h | |
if @world.debug | |
@world.ctx.strokeStyle = @color | |
@world.ctx.strokeRect @rX, @rY, @w, @h | |
if @image.ready | |
sx = ( @w * @frame ) | |
sy = 0 | |
@world.ctx.drawImage( @image.image, sx, sy, @w, @h, @rX , @rY, @w, @h ) | |
setFlags: (flag)-> | |
@flags[flag] = true | |
clearFlags: (flag)-> | |
@flags[flag] = false | |
getTileFrame: -> | |
tileFrames= | |
0: 0, | |
1: 0, | |
2: 4, | |
3: 5, | |
4: 6, | |
5: 7 | |
tileFrames[@type] | |
getType: -> | |
tileTypes= | |
'tile': 'images/gameTile.png', | |
'isoTile': 'images/gameTileIso.png', | |
type = if @world.iso then 'isoTile' else 'tile' | |
tileTypes[type] | |
class DrawnTile extends Tile | |
colour: '' | |
constructor: (@world, @x, @y, @w, @h, @type = 0, @tileNo = [0, 0], @walkable=true) -> | |
@defaultColour = '#d6abb1' | |
if @type is 1 then @defaultColour = '#d9d9d9' | |
super | |
update: (modifier)-> | |
@rX = @x - @world.scrollX | |
@rY = @y - @world.scrollY | |
@colour = @defaultColour | |
if @flags.path | |
@colour = @getColour 'path' | |
if @flags.hover | |
@colour = @getColour 'hover' | |
if @flags.selected | |
@colour = @getColour 'selected' | |
draw: -> | |
@world.ctx.fillStyle = @colour | |
@world.ctx.beginPath() | |
@world.ctx.moveTo @rX + (@world.tileWidth / 2), @rY | |
@world.ctx.lineTo @rX + @world.tileWidth, @rY + (@world.tileHeight / 2) | |
@world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY + @world.tileHeight | |
@world.ctx.lineTo @rX, @rY + (@world.tileHeight / 2) | |
@world.ctx.closePath() | |
@world.ctx.fill() | |
getColour: (flag) -> | |
colours= | |
hover: '#cd8791', | |
selected: 'white', | |
path: '#de98a2' | |
colours[flag] | |
### | |
~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ | |
~The Entity Class | |
~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ | |
### | |
class Entity extends Sprite | |
speed:0 | |
vx: 0 | |
vy:0 | |
constructor: (@world, @x, @y, @w, @h, image, @speed) -> | |
@frame = 0 | |
@w *= @world.scale | |
@h *= @world.scale | |
@speedX *= @world.scale | |
@speedY *= @world.scale | |
console.log 'created a ' + @name | |
super @world, image | |
update: (modifier) -> | |
@vx = 0 unless @nextX != @x | |
@vy = 0 unless @nextY != @y | |
if @vx == 0 and @vy == 0 | |
if @path and @path[2] | |
@path.shift() | |
@walkPath @path | |
@x += @vx | |
@y += @vy | |
@rX = @x - @world.scrollX | |
@rY = @y - @world.scrollY | |
draw: -> | |
if @image.ready | |
sx = ( @w * @frame ) | |
sy = 0 | |
@world.ctx.drawImage( @image.image, sx, sy, @w, @h, @rX - (@w - @world.tileWidth), @rY - (@h - @world.tileHeight), @w * @world.scale, @h*@world.scale ) | |
twoDToIso: (x, y, w, h)-> | |
tileX = Math.floor ( (@rX + @world.scrollX) / @world.tileWidth ) + ( (@rY + @world.scrollY) / @world.tileHeight) | |
tileY = Math.floor ( (@rY + @world.scrollY) / @world.tileHeight ) - ( (@rX + @world.scrollX) / @world.tileWidth) | |
{x: tileX, y:tileY} | |
getTile:(x = @rX, y=@rY) => | |
if @world.iso | |
matrix = @twoDToIso x, y, @world.tileWidth, @world.tileHeight | |
else | |
px = Math.floor @rX / @world.tileWidth | |
py = Math.floor @rY / @world.tileHeight | |
matrix = {x: Math.floor(@x / @world.tileWidth), y: Math.floor (@y / @world.tileHeight)} | |
matrix | |
walkPath: (path) -> | |
@path = path | |
if @path[1] | |
@nextStep = @path[1] | |
@nextX = @world.background.mapTiles[@nextStep[1]][@nextStep[0]].x | |
@nextY = @world.background.mapTiles[@nextStep[1]][@nextStep[0]].y | |
deltaX = @nextX - @x | |
deltaY = @nextY - @y | |
if deltaX != 0 | |
if deltaX > 0 | |
#move right | |
@vx = @speedX | |
if deltaX < 0 | |
#move left | |
@vx = -@speedX | |
if deltaY != 0 | |
if deltaY > 0 | |
#move down | |
@vy = @speedY | |
if deltaY < 0 | |
#move up | |
@vy = -@speedY | |
else | |
false | |
### | |
~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ | |
~The Player Class | |
~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ | |
### | |
class Player extends Entity | |
name: 'Player' | |
constructor: -> | |
@speedX = 3 | |
@speedY = 3 | |
super | |
if @world.iso | |
@speedX *= 2 | |
@world.player = this | |
update:(modifier) -> | |
super | |
draw: -> | |
super | |
if @world.debug | |
@world.ctx.strokeStyle = 'black' | |
@world.ctx.strokeRect @rX , @rY , @w, @h | |
class DrawnPlayer extends Player | |
constructor: -> | |
@colourTop = '#c4ffeb' | |
@colourRight = '#9be1c9' | |
@colourLeft = '#80b9a6' | |
super | |
draw: -> | |
@world.ctx.fillStyle = @colourLeft | |
@world.ctx.beginPath() | |
@world.ctx.moveTo @rX, @rY + @world.tileHeight / 2 | |
@world.ctx.lineTo @rX, @rY - @world.tileHeight / 2 | |
@world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY - (@world.tileHeight) | |
@world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY + @world.tileHeight | |
@world.ctx.closePath() | |
@world.ctx.fill() | |
@world.ctx.fillStyle = @colourRight | |
@world.ctx.beginPath() | |
@world.ctx.moveTo @rX + @w, @rY + @world.tileHeight / 2 | |
@world.ctx.lineTo @rX + @w, @rY - @world.tileHeight / 2 | |
@world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY - (@world.tileHeight) | |
@world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY + @world.tileHeight | |
@world.ctx.closePath() | |
@world.ctx.fill() | |
@world.ctx.fillStyle = @colourTop | |
@world.ctx.beginPath() | |
@world.ctx.moveTo @rX + @w, @rY - @world.tileHeight / 2 | |
@world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY - (@world.tileHeight) | |
@world.ctx.lineTo @rX, @rY - @world.tileHeight / 2 | |
@world.ctx.lineTo @rX + (@world.tileWidth / 2), @rY | |
@world.ctx.closePath() | |
@world.ctx.fill() | |
if @world.debug | |
@strokeStyle = 'black' | |
@world.ctx.strokeRect(@rX, @rY, @w, @h) | |
@strokeStyle = 'blue' | |
@world.ctx.strokeRect @rX, @rY, 4, 4 | |
### | |
~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ | |
~The helpers | |
~~~~~~~~~~~~~~~~~ | |
~~~~~~~~~~~~~~~~~ | |
getTwoDPoint = (world, x, y)-> | |
px = Math.floor x / world.tileWidth | |
py = Math.floor y / world.tileHeight | |
getIsoPoint = (world, x, y) -> | |
px = 'howdy' | |
### | |
class Clone | |
constructor:(obj) -> | |
if not obj? or typeof obj isnt 'object' | |
return obj | |
if obj instanceof Date | |
return new Date(obj.getTime()) | |
if obj instanceof RegExp | |
flags = '' | |
flags += 'g' if obj.global? | |
flags += 'i' if obj.ignoreCase? | |
flags += 'm' if obj.multiline? | |
flags += 'y' if obj.sticky? | |
return new RegExp(obj.source, flags) | |
newInstance = new obj.constructor() | |
for key of obj | |
newInstance[key] = @clone obj[key] | |
newInstance | |
### | |
START THE GAME! | |
### | |
map2 = [ | |
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], | |
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1], | |
[1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,1], | |
[1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,1], | |
[1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,1], | |
[1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,1], | |
[1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,1,0,1], | |
[1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,1,1,0,1], | |
[1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,1,1,0,1], | |
[1,0,0,0,0,0,1,1,1,0,0,0,1,0,0,0,1,0,0,1,1,0,1], | |
[1,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1], | |
[1,0,0,0,0,0,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1], | |
[1,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,1,0,0,0,0,1], | |
[1,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,0,1], | |
[1,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,1,1,1,0,1], | |
[1,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,1], | |
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], | |
] | |
map = [ | |
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], | |
[1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,1], | |
[1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,1], | |
[1,1,1,1,0,0,0,0,1,1,1,1,1,0,1,0,0,0,0,1], | |
[1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0,0,0,1], | |
[1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,0,1], | |
[1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1], | |
[1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,0,1], | |
[1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1], | |
[1,1,1,1,1,0,1,1,1,1,1,0,0,0,0,0,0,0,1,1], | |
[1,0,0,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1], | |
[1,0,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1], | |
[1,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1], | |
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], | |
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], | |
] | |
window.onload = -> | |
game = new Game 'game', 30, scale:.5 | |
game.iso = true | |
game.run() | |
game.world.createWorld map | |
game.world.scrollX = -250 | |
#game.world.debug = true | |
### | |
bind mousey | |
### | |
$('canvas').on('click', ()-> | |
game.inputHandler.clicked = true | |
) | |
pX = game.world.background.mapTiles[2][17].rX | |
pY = game.world.background.mapTiles[2][17].rY | |
player = new DrawnPlayer game.world,pX, pY, 60, 60, 'images/player.png', 10 | |
#for the demo | |
### | |
thePath = [[8,7],[7,7],[6,7],[6,6],[6,5], [5,5], [4,5], [4, 4], [4, 3]] | |
game.world.background.mapTiles[3][4].setFlags 'selected' | |
### | |
#whoodle demo | |
thePath = [[17,2], [16,2], [16,3], [16,4], [15,4], [14,4], [13,4], [13,3], [13,2]] | |
game.world.background.mapTiles[2][13].setFlags 'selected' | |
for tile in thePath | |
game.world.background.mapTiles[tile[1]][tile[0]].setFlags 'path' | |
player.walkPath thePath | |
@import "compass"; | |
.clearfix { | |
zoom: 1; | |
&:before, &:after { content: ""; display: table; } | |
&:after { clear: both; } | |
} | |
@mixin css-gradient($from: #dfdfdf, $to: #f8f8f8) { | |
background-color: $to; | |
background-image: -webkit-gradient(linear, left top, left bottom, from($from), to($to)); | |
background-image: -webkit-linear-gradient(top, $from, $to); | |
background-image: -moz-linear-gradient(top, $from, $to); | |
background-image: -o-linear-gradient(top, $from, $to); | |
background-image: linear-gradient(to bottom, $from, $to); | |
} | |
@mixin box-sizing($type: border-box) { | |
-webkit-box-sizing: $type; | |
-moz-box-sizing: $type; | |
-ms-box-sizing: $type; | |
box-sizing: $type; | |
} | |
@mixin prefix($prop, $value){ | |
-webkit-#{$prop}: $value; -moz-#{$prop}: $value; -o-#{$prop}: $value; -ms-#{$prop}: $value; | |
} | |
@mixin listfix(){ | |
display:block; padding:0; margin:0 0 0; list-style:none; | |
} | |
//colours | |
$black: #312736; | |
$red: #d4838f; | |
$greyred: #d6abb1; | |
$grey: #d9d9d9; | |
$blue: #c4ffeb; | |
* {box-sizing:border-box; } | |
body{ | |
display:block; | |
background:$grey; | |
} | |
#wrapper { | |
display:block; | |
width:90%; | |
height:auto; | |
margin:0 auto; | |
} |