| @@ -0,0 +1,2 @@ | |||||
| # ld40 | |||||
| Ludum Dare 40 - Theme : "The more you have, the worse it is" | |||||
| @@ -0,0 +1,56 @@ | |||||
| <html> | |||||
| <head> | |||||
| <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/> | |||||
| <meta property="og:image" content="http://ncannasse.fr/file/ld40/screen.png"/> | |||||
| <link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'/> | |||||
| <title>Taffle Game</title> | |||||
| </head> | |||||
| <body style="background-color : #F9F7F7; color : #eef"> | |||||
| <style type="text/css"> | |||||
| a { | |||||
| color : #844; | |||||
| text-decoration : none; | |||||
| } | |||||
| p { | |||||
| color : #888; | |||||
| font-family: 'Open Sans', sans-serif; | |||||
| } | |||||
| </style> | |||||
| <center> | |||||
| <div style="position : relative; width : 832px"> | |||||
| <canvas id="webgl" style="width:832px;height:832px"></canvas> | |||||
| </div> | |||||
| <p> | |||||
| <b>Arrows</b> : Move / <b>Space</b> : Rewind | |||||
| - | |||||
| <i>Game created for LudumDare #40 in 48 hours by <a href="http://twitter.com/ncannasse">@ncannasse</a></i> | |||||
| </p> | |||||
| <p> | |||||
| Sources : <a href="http://github.com/ncannasse/ld40">Github</a> | Built with <a href="http://haxe.org">Haxe</a> | Rate <a href="https://ldjam.com/events/ludum-dare/40/jonathan-the-sorcerer">on this page</a> | |||||
| </p> | |||||
| </center> | |||||
| <script type="text/javascript" src="ld40.js"></script> | |||||
| <script type="text/javascript"> | |||||
| var _gaq = _gaq || []; | |||||
| _gaq.push(['_setAccount', 'UA-34409935-1']); | |||||
| _gaq.push(['_trackPageview']); | |||||
| (function() { | |||||
| var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; | |||||
| ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; | |||||
| var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); | |||||
| })(); | |||||
| </script> | |||||
| </body> | |||||
| </html> | |||||
| @@ -0,0 +1,8 @@ | |||||
| -lib heaps | |||||
| -lib castle | |||||
| -cp src | |||||
| -js ld40.js | |||||
| -main Game | |||||
| -D windowSize=832x832 | |||||
| -dce full | |||||
| -D release | |||||
| @@ -0,0 +1,28 @@ | |||||
| { "compressionlevel":-1, | |||||
| "height":20, | |||||
| "infinite":false, | |||||
| "layers":[ | |||||
| { | |||||
| "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |||||
| "height":20, | |||||
| "id":1, | |||||
| "name":"Tile Layer 1", | |||||
| "opacity":1, | |||||
| "type":"tilelayer", | |||||
| "visible":true, | |||||
| "width":20, | |||||
| "x":0, | |||||
| "y":0 | |||||
| }], | |||||
| "nextlayerid":2, | |||||
| "nextobjectid":1, | |||||
| "orientation":"orthogonal", | |||||
| "renderorder":"right-down", | |||||
| "tiledversion":"2020.04.10", | |||||
| "tileheight":32, | |||||
| "tilesets":[], | |||||
| "tilewidth":32, | |||||
| "type":"map", | |||||
| "version":1.2, | |||||
| "width":20 | |||||
| } | |||||
| @@ -0,0 +1 @@ | |||||
| private typedef Init = haxe.macro.MacroType < [cdb.Module.build("data.cdb")] > ; | |||||
| @@ -0,0 +1,489 @@ | |||||
| import hxd.res.DynamicText.Key; | |||||
| import h3d.pass.Default; | |||||
| import ent.Entity; | |||||
| import ent.Object; | |||||
| import hxd.Key in K; | |||||
| class EnvPart extends h2d.SpriteBatch.BatchElement { | |||||
| public var speed : Float; | |||||
| public var rspeed : Float; | |||||
| public function new(t) { | |||||
| super(t); | |||||
| x = Math.random() * Game.LW * 32; | |||||
| y = Math.random() * Game.LH * 32; | |||||
| speed = 6 + Math.random() * 3; | |||||
| rspeed = 0.02 * (1 + Math.random()); | |||||
| } | |||||
| } | |||||
| @:publicFields | |||||
| class Game extends hxd.App { | |||||
| static var LW = 13; | |||||
| static var LH = 13; | |||||
| static var LAYER_SOIL = 0; | |||||
| static var LAYER_ENT_UNDER = 1; | |||||
| static var LAYER_COL = 2; | |||||
| static var LAYER_ENT = 3; | |||||
| static var LAYER_CARRY = 4; | |||||
| static var LAYER_HERO = 5; | |||||
| static var LAYER_PARTS = 6; | |||||
| static var LAYER_ENVP = 7; | |||||
| static var LAYER_END = 8; | |||||
| var currentLevel : Int; | |||||
| var tiles : h2d.Tile; | |||||
| var level : Data.Level; | |||||
| var soils : Array<Data.Soil>; | |||||
| var entities : Array<ent.Entity> = []; | |||||
| var world : h2d.Layers; | |||||
| var dbgCol : h2d.TileGroup; | |||||
| var soilLayer : h2d.TileGroup; | |||||
| var pad : hxd.Pad; | |||||
| var allActive : Bool; | |||||
| var bg : h2d.Object; | |||||
| var clouds = []; | |||||
| var parts : h2d.SpriteBatch; | |||||
| var way : Float = 1.; | |||||
| var bmpTrans : h2d.Bitmap; | |||||
| var hueShaderHalf = new h3d.shader.ColorMatrix(); | |||||
| var hueValue = 0; | |||||
| var title : h2d.Bitmap; | |||||
| var end : h2d.Bitmap; | |||||
| var errorSound: hxd.res.Sound; | |||||
| function loadGame() { | |||||
| haxe.Timer.delay(function() { | |||||
| for( e in entities.copy() ) | |||||
| if( e.hasFlag(NeedActive) ) | |||||
| e.remove(); | |||||
| bg.visible = false; | |||||
| parts.visible = false; | |||||
| var t = new h3d.mat.Texture(LW * 32, LH * 32, [Target]); | |||||
| var old = world.filter; | |||||
| world.filter = null; | |||||
| world.drawTo(t); | |||||
| world.filter = old; | |||||
| bmpTrans = new h2d.Bitmap(h2d.Tile.fromTexture(t)); | |||||
| bg.visible = true; | |||||
| parts.visible = true; | |||||
| initLevel(); | |||||
| world.add(bmpTrans, LAYER_ENT - 1); | |||||
| },0); | |||||
| } | |||||
| function initLevel() | |||||
| { | |||||
| level = Data.level.all[currentLevel]; | |||||
| if( level == null ) | |||||
| return; | |||||
| soils = level.soils.decode(Data.soil.all); | |||||
| while( soilLayer.numChildren > 0 ) | |||||
| soilLayer.getChildAt(0).remove(); | |||||
| // Build game board | |||||
| var empty = tiles.sub(0, 2 * 32, 32, 32); | |||||
| var edgeTile = tiles.sub(2*32, 2 * 32, 32, 32); | |||||
| soilLayer.clear(); | |||||
| for( y in 0...LH ) { | |||||
| for( x in 0...LW ) { | |||||
| var index = x + y * LW; | |||||
| var s = soils[x + y * LW]; | |||||
| if(x > 1 && x < 11 && y > 1 && y < 11) | |||||
| { | |||||
| // check if it is the corner or center tile | |||||
| if((x==y || (x + y) == 12)&& (x == 2 || x == 6 || x == 10) ) | |||||
| { | |||||
| soilLayer.add(x * 32, y * 32, edgeTile); | |||||
| } | |||||
| else | |||||
| { | |||||
| soilLayer.add(x * 32, y * 32, empty); | |||||
| } | |||||
| } | |||||
| // place object on the board | |||||
| createObject(x, y); | |||||
| } | |||||
| } | |||||
| // Handle interactions | |||||
| var prevKind = null; | |||||
| var clickedObjKind = null; | |||||
| var clickedObj = null; | |||||
| var isFirstClick = true; | |||||
| var sX = 0, sY = 0; | |||||
| var eX = 0, eY = 0; | |||||
| var interaction = new h2d.Interactive(1000, 1000, soilLayer); | |||||
| var count = 0; | |||||
| interaction.onClick = function(event : hxd.Event) { | |||||
| var xPos = Std.int((event.relX)/32); | |||||
| var yPos = Std.int((event.relY)/32); | |||||
| if (isFirstClick == true){ | |||||
| sX = xPos; | |||||
| sY = yPos; | |||||
| //trace (isFirstClick); | |||||
| clickedObj = Std.downcast(pick(sX, sY), Object); | |||||
| if(clickedObj != null) | |||||
| { | |||||
| isFirstClick = false; | |||||
| // Treat the purple circle and the purple gem as same kind | |||||
| if (isKing(clickedObj.kind)) | |||||
| clickedObjKind = Data.ObjectKind.Exit; | |||||
| else | |||||
| clickedObjKind = clickedObj.kind; | |||||
| } | |||||
| } | |||||
| else{ | |||||
| trace (prevKind); | |||||
| eX = xPos; | |||||
| eY = yPos; | |||||
| isFirstClick = true; | |||||
| //trace (isFirstClick); | |||||
| var destinationObj = Std.downcast(pick(eX, eY), Object); | |||||
| var isAcceptableMove = true; | |||||
| if (destinationObj == null && // destination tile is empty | |||||
| clickedObj != null && // you have clicked an object to move | |||||
| prevKind != clickedObjKind && // alternating turns | |||||
| (eX == sX || eY == sY)) // moving horizontally or vertically | |||||
| { | |||||
| // Check that there are no blockade between start and end | |||||
| var isHorizontal = false; | |||||
| var distanceToMove = 0; | |||||
| var tempX = sX; | |||||
| var tempY = sY; | |||||
| if (eX == sX){ | |||||
| distanceToMove = eY - sY; | |||||
| if (distanceToMove < 0){ | |||||
| tempY--; | |||||
| } | |||||
| else{ | |||||
| tempY++; | |||||
| } | |||||
| } | |||||
| else if (eY == sY){ | |||||
| isHorizontal = true; | |||||
| distanceToMove = eX - sX; | |||||
| if (distanceToMove < 0){ | |||||
| tempX--; | |||||
| } | |||||
| else{ | |||||
| tempX++; | |||||
| } | |||||
| } | |||||
| trace ('sX, sY: ' + sX + ',' + sY); | |||||
| trace ('eX, eY: ' + eX + ',' + eY); | |||||
| trace ('isHorizontal: ' + isHorizontal); | |||||
| trace ('distanceToMove: ' + distanceToMove); | |||||
| while (distanceToMove != 0){ | |||||
| var oB = Std.downcast(pick(tempX, tempY), Object); | |||||
| trace ('tempX, tempY: ' + tempX + ',' + tempY); | |||||
| if (oB == null && isHorizontal){ | |||||
| if (distanceToMove < 0) | |||||
| tempX--; | |||||
| else | |||||
| tempX++; | |||||
| } | |||||
| else if (oB == null && !isHorizontal){ | |||||
| if (distanceToMove < 0) | |||||
| tempY--; | |||||
| else | |||||
| tempY++; | |||||
| } | |||||
| else if (oB != null){ | |||||
| trace ('oB is not null '); | |||||
| isAcceptableMove = false; | |||||
| break; | |||||
| } | |||||
| if (distanceToMove > 0) | |||||
| distanceToMove--; | |||||
| else | |||||
| distanceToMove++; | |||||
| } | |||||
| // check if a non-player object is moving to the cornre | |||||
| if((eX == 2 || eX == 10) && (eY == 2 || eY == 10)) | |||||
| { | |||||
| if (!isKing(clickedObj.kind)){ | |||||
| isAcceptableMove = false; | |||||
| } | |||||
| } | |||||
| // Move the object | |||||
| if (isAcceptableMove){ | |||||
| // remove from the source position | |||||
| clickedObj.remove(); | |||||
| // create the object in the destination position | |||||
| var movedObj = new ent.Object(clickedObj.kind, eX, eY); | |||||
| if ((eX == 2 || eX == 10) && (eY == 2 || eY == 10)){ | |||||
| // End game if reached the corner | |||||
| if (isKing(movedObj.kind)){ | |||||
| displayEnd(); | |||||
| } | |||||
| } | |||||
| prevKind = clickedObjKind; | |||||
| //To Do: Add Logic for Capture | |||||
| /*if (eX == sX){ | |||||
| if (distanceToMove > 0){ | |||||
| var obJ = Std.downcast(pick(eX, eY + 2), Object); | |||||
| var Obj = Std.downcast(pick(eX, eY + 1), Object); | |||||
| if (obJ != null && Obj != null){ | |||||
| if (obJ.kind == movedObj.kind && Obj.kind != movedObj.kind){ | |||||
| if (movedObj.kind == Square3) | |||||
| movedObj.kind = Exit; | |||||
| else if (obJ.kind == Square3){ | |||||
| obJ.kind = Exit; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| }*/ | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| isAcceptableMove = false; | |||||
| } | |||||
| if(!isAcceptableMove && errorSound != null) | |||||
| { | |||||
| errorSound.play(false, 0.5 + Math.random() * 0.5); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| function displayEnd() { | |||||
| end = new h2d.Bitmap(hxd.Res.end_png.toTile()); | |||||
| end.scale(1); | |||||
| world.add(end, LAYER_END); | |||||
| // Pause for 5 sec and then end the game | |||||
| haxe.Timer.delay(function() { | |||||
| Game.restartGame(); | |||||
| }, 5000); | |||||
| } | |||||
| function createObject(x, y) : ent.Entity { | |||||
| var myX = x * 1; | |||||
| var myY = y * 1; | |||||
| if(x==6 && y == 6) | |||||
| { | |||||
| return new ent.Object(Square2, x, y); | |||||
| } | |||||
| else if ( ((x > 4 && x < 8) && ((y == 2) || (y == 10))) || | |||||
| ((y > 4 && y < 8) && ((x == 2) || (x == 10))) || | |||||
| (x == 6 && (y == 3 || y == 9)) || | |||||
| (y == 6 && (x == 3 || x == 9)) | |||||
| ) | |||||
| { | |||||
| return new ent.Object(Square1, x, y); | |||||
| } | |||||
| else if ( (x == 6 && (y > 3 && y < 6)) || | |||||
| (x == 6 && (y > 6 && y < 9)) || | |||||
| (y == 6 && (x > 3 && x < 6)) || | |||||
| (y == 6 && (x > 6 && x < 9)) | |||||
| ) | |||||
| { | |||||
| return new ent.Object(Exit, x, y); | |||||
| } | |||||
| return null; | |||||
| } | |||||
| function isKing(kind : Data.ObjectKind ){ | |||||
| return (kind == Square2); | |||||
| } | |||||
| function getSoil( x, y ) : Data.SoilKind { | |||||
| if( x < 0 || y < 0 || x >= LW || y >= LH ) | |||||
| return Block; | |||||
| return soils[x + y * LH].id; | |||||
| } | |||||
| function pick( x : Float, y : Float ) { | |||||
| var ix = Std.int(x); | |||||
| var iy = Std.int(y); | |||||
| for( e in entities ) | |||||
| { | |||||
| if( Std.int(e.x) == ix && Std.int(e.y) == iy ) | |||||
| { | |||||
| return e; | |||||
| } | |||||
| } | |||||
| return null; | |||||
| } | |||||
| override function init() { | |||||
| errorSound = hxd.Res.load("sfx/error.wav").toSound(); | |||||
| // preload sounds | |||||
| for( s in hxd.Res.load("sfx") ) | |||||
| s.toSound().getData(); | |||||
| s2d.scaleMode = Stretch(LW * 32, LH * 32); | |||||
| currentLevel = 1; | |||||
| world = new h2d.Layers(s2d); | |||||
| world.filter = new h2d.filter.Bloom(0.5,0.2,3); | |||||
| tiles = hxd.Res.tiles.toTile(); | |||||
| soilLayer = new h2d.TileGroup(tiles); | |||||
| bg = new h2d.Object(world); | |||||
| bg.filter = new h2d.filter.Blur(3); | |||||
| bg.filter.smooth = true; | |||||
| var tbg = tiles.sub(32 * 3, 64, 32, 32); | |||||
| tbg.scaleToSize(LW * 32, LH * 32); | |||||
| new h2d.Bitmap(tbg, bg).addShader(hueShaderHalf); | |||||
| // Display background clouds | |||||
| var rnd = new hxd.Rand(42); | |||||
| var ctiles = [for( i in 0...3 ) tiles.sub(i * 32 * 3, 192, 32 * 3, 64, -32 * 3 >> 1, -32)]; | |||||
| for( i in 0...100 ) { | |||||
| var b = new h2d.Bitmap(ctiles[rnd.random(ctiles.length)], bg); | |||||
| b.smooth = true; | |||||
| b.addShader(hueShaderHalf); | |||||
| clouds.push({ sc : 0.7 + rnd.rand(), x : rnd.rand() * (LW * 32 + 200) - 100, y : rnd.rand() * (LH * 32 + 200) - 100, speed : rnd.rand() + 1, spr : b, t : Math.random() * Math.PI * 2 }); | |||||
| } | |||||
| // Display the flying snow | |||||
| var ptiles = hxd.Res.envParts.toTile().split(); | |||||
| parts = new h2d.SpriteBatch(ptiles[0]); | |||||
| world.add(parts, LAYER_ENVP); | |||||
| for( i in 0...100 ) | |||||
| parts.add(new EnvPart(ptiles[Std.random(ptiles.length)])); | |||||
| world.add(soilLayer, LAYER_SOIL); | |||||
| pad = hxd.Pad.createDummy(); | |||||
| hxd.Pad.wait(function(p) pad = p); | |||||
| // Display title and instruction to start game | |||||
| title = new h2d.Bitmap(hxd.Res.title.toTile(), world); | |||||
| var tf = new h2d.Text(hxd.res.DefaultFont.get(), title); | |||||
| tf.textColor = 0; | |||||
| tf.text = "Press space to start"; | |||||
| tf.x=180; | |||||
| tf.y = 180; | |||||
| } | |||||
| override function update( dt : Float ) { | |||||
| dt *= 60; // old dt support | |||||
| if( bmpTrans != null ) { | |||||
| bmpTrans.alpha -= 0.05 * dt; | |||||
| if( bmpTrans.alpha < 0 ) { | |||||
| bmpTrans.tile.getTexture().dispose(); | |||||
| bmpTrans.remove(); | |||||
| bmpTrans = null; | |||||
| } | |||||
| } | |||||
| for( e in entities.copy() ) | |||||
| e.update(dt); | |||||
| var ang = -0.3; | |||||
| for( c in clouds ) { | |||||
| var ds = c.speed * dt * 0.3 * way; | |||||
| c.t += ds * 0.01; | |||||
| c.spr.setScale(1 + Math.sin(c.t) * 0.2); | |||||
| c.spr.scaleX *= c.sc; | |||||
| c.x += Math.cos(ang) * ds; | |||||
| c.y += Math.sin(ang) * ds; | |||||
| c.spr.x = c.x; | |||||
| c.spr.y = c.y; | |||||
| if( c.x > LW * 32 + 100 ) | |||||
| c.x -= LW * 32 + 300; | |||||
| if( c.y > LH * 32 + 100 ) | |||||
| c.y -= LH * 32 + 300; | |||||
| if( c.x < -100 ) | |||||
| c.x += LW * 32 + 300; | |||||
| if( c.y < -100 ) | |||||
| c.y += LH * 32 + 300; | |||||
| } | |||||
| parts.hasRotationScale = true; | |||||
| for( p in parts.getElements() ) { | |||||
| var p = cast(p, EnvPart); | |||||
| var ds = dt * p.speed * way; | |||||
| p.x += Math.cos(ang) * ds; | |||||
| p.y += Math.sin(ang) * ds; | |||||
| p.rotation += ds * p.rspeed; | |||||
| if( p.x > LW * 32 ) | |||||
| p.x -= LW * 32; | |||||
| if( p.y > LH * 32 ) | |||||
| p.y -= LH * 32; | |||||
| if( p.y < 0 ) | |||||
| p.y += LH * 32; | |||||
| if( p.x < 0 ) | |||||
| p.x += LW * 32; | |||||
| } | |||||
| if( title != null && title.alpha < 1 ) { | |||||
| title.alpha -= 0.01 * dt; | |||||
| if( title.alpha < 0 ) { | |||||
| title.remove(); | |||||
| title = null; | |||||
| } | |||||
| } | |||||
| if( title != null && title.alpha == 1 ) { | |||||
| if(K.isPressed(K.SPACE)) { | |||||
| title.alpha = 0.99; | |||||
| loadGame(); | |||||
| } | |||||
| } | |||||
| } | |||||
| public static var inst : Game; | |||||
| static function main() { | |||||
| #if js | |||||
| hxd.Res.initEmbed(); | |||||
| #else | |||||
| hxd.res.Resource.LIVE_UPDATE = true; | |||||
| hxd.Res.initLocal(); | |||||
| #end | |||||
| Data.load(hxd.Res.data.entry.getText()); | |||||
| inst = new Game(); | |||||
| } | |||||
| static function restartGame() { | |||||
| Game.main(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,81 @@ | |||||
| package ent; | |||||
| class Entity { | |||||
| var game : Game; | |||||
| public var inf : Data.Object; | |||||
| public var kind : Data.ObjectKind; | |||||
| public var x : Float; | |||||
| public var y : Float; | |||||
| public var spr : h2d.Anim; | |||||
| public function new( kind, x : Int, y : Int ) { | |||||
| game = Game.inst; | |||||
| this.kind = kind; | |||||
| inf = Data.object.get(kind); | |||||
| this.x = x + 0.5; | |||||
| this.y = y + 0.5; | |||||
| spr = new h2d.Anim(getAnim(), 15); | |||||
| game.world.add(spr, hasFlag(Under) ? Game.LAYER_ENT_UNDER : Game.LAYER_ENT); | |||||
| game.entities.push(this); | |||||
| } | |||||
| public function hasFlag(f) { | |||||
| return inf.flags.has(f); | |||||
| } | |||||
| public function isOccupied() { | |||||
| if( getObj(Std.int(x), Std.int(y)) != null ) | |||||
| return true; | |||||
| return false; | |||||
| } | |||||
| public function isCollide( with : ent.Entity ) { | |||||
| return true; | |||||
| } | |||||
| function getObj( x : Int, y : Int, ?k : Data.ObjectKind, ?flags : Array<Data.Object_flags> ) { | |||||
| for( e in game.entities ) { | |||||
| var o = Std.downcast(e, Object); | |||||
| if( o == null || o.carried || o == this ) continue; | |||||
| if( Std.int(o.x) != x || Std.int(o.y) != y ) continue; | |||||
| if( flags != null ) { | |||||
| var ok = true; | |||||
| for( f in flags ) | |||||
| if( !o.inf.flags.has(f) ) { | |||||
| ok = false; | |||||
| break; | |||||
| } | |||||
| if( !ok ) continue; | |||||
| } | |||||
| if( k == null || o.kind == k ) | |||||
| return o; | |||||
| } | |||||
| return null; | |||||
| } | |||||
| public function canPick() { | |||||
| return false; | |||||
| } | |||||
| public function remove() { | |||||
| spr.remove(); | |||||
| game.entities.remove(this); | |||||
| } | |||||
| function getAnim() { | |||||
| return [game.tiles.sub(inf.image.x * 32, inf.image.y * 32, 32, 32, -16, -16)]; | |||||
| } | |||||
| public function update( dt : Float ) { | |||||
| spr.x = Std.int(x * 64) / 2; | |||||
| spr.y = Std.int(y * 64) / 2; | |||||
| } | |||||
| function toString() { | |||||
| return kind + "(" + Std.int(x) + "," + Std.int(y) + ")"; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,132 @@ | |||||
| package ent; | |||||
| import Data.ObjectKind; | |||||
| class Object extends Entity { | |||||
| var speed = 0.2; | |||||
| var angle = 0.; | |||||
| var wasCarried = false; | |||||
| var color : h3d.shader.ColorAdd; | |||||
| var pulse : Float = 0.; | |||||
| var hintAct : h2d.Anim; | |||||
| public var active : Bool; | |||||
| public var carried(default, set) : Bool = false; | |||||
| public function new(k, x, y) { | |||||
| super(k, x, y); | |||||
| switch( kind ) { | |||||
| case Square1, Square2, Square3, Wings: | |||||
| var a = new h2d.Anim([for( i in 0...9 ) game.tiles.sub(i * 32, 256 + (kind == Wings ? 64 : kind == Square2 ? 32 : 0), 32, 32, -16, -16)], 20, spr); | |||||
| a.loop = false; | |||||
| a.onAnimEnd = function() { | |||||
| haxe.Timer.delay(function() { | |||||
| a.currentFrame = 0; | |||||
| }, 200 + Std.random(400)); | |||||
| }; | |||||
| if( kind == Square3 ) | |||||
| a.adjustColor({ hue : Math.PI / 2 }); | |||||
| hintAct = a; | |||||
| case Plate1, Plate2, Plate3, Plate4: | |||||
| game.soilLayer.add(Std.int(x) * 32, Std.int(y) * 32, game.tiles.sub(64, 32, 32, 32)); | |||||
| spr.alpha = 0.8; | |||||
| case Hero: | |||||
| game.soilLayer.add(Std.int(x) * 32, Std.int(y) * 32, game.tiles.sub(0, 96, 32, 32)); | |||||
| spr.alpha = 1; | |||||
| default: | |||||
| } | |||||
| } | |||||
| function set_carried(b) { | |||||
| var ix = Std.int(x); | |||||
| var iy = Std.int(y); | |||||
| if( b ) | |||||
| active = false; | |||||
| wasCarried = carried; | |||||
| game.world.add(spr, b ? Game.LAYER_CARRY : Game.LAYER_ENT); | |||||
| return carried = b; | |||||
| } | |||||
| override function isCollide( with : ent.Entity ) { | |||||
| return with != null && with.kind != Hero; | |||||
| } | |||||
| override function canPick() { | |||||
| if( hasFlag(Under) ) | |||||
| return false; | |||||
| if( carried ) | |||||
| return false; | |||||
| return true; | |||||
| } | |||||
| override function getAnim() { | |||||
| return switch( kind ) { | |||||
| case Exit: | |||||
| [for( i in 0...6 ) game.tiles.sub(i * 32, 160, 32, 32, -16, -16)]; | |||||
| default: | |||||
| super.getAnim(); | |||||
| } | |||||
| } | |||||
| override public function update(dt:Float) { | |||||
| if( hintAct != null ) | |||||
| hintAct.visible = !active; | |||||
| else if( active ) { | |||||
| pulse += dt * 0.1; | |||||
| spr.adjustColor({ saturation : Math.abs(Math.sin(pulse)) * 0.5, lightness : Math.abs(Math.sin(pulse)) * 0.2 }); | |||||
| } else if( pulse != 0 ) { | |||||
| pulse %= Math.PI; | |||||
| pulse += dt * 0.1; | |||||
| if( pulse > Math.PI ) | |||||
| pulse = 0; | |||||
| spr.adjustColor({ saturation : Math.abs(Math.sin(pulse)) * 0.5, lightness : Math.abs(Math.sin(pulse)) * 0.2 }); | |||||
| } | |||||
| if( spr.scaleX < 1 ) { | |||||
| spr.scale(Math.pow(1.05, dt)); | |||||
| if( spr.scaleX > 1 ) { | |||||
| spr.setScale(1); | |||||
| spr.smooth = false; | |||||
| } | |||||
| } | |||||
| var ix = Std.int(x), iy = Std.int(y); | |||||
| switch( kind ) { | |||||
| case Exit: | |||||
| if( game.allActive ) { | |||||
| spr.speed = 15; | |||||
| } else { | |||||
| spr.speed = 0; | |||||
| spr.currentFrame = 0; | |||||
| } | |||||
| case Square1: | |||||
| active = getObj(ix, iy, [Plate1, Plate2][game.hueValue], [CanPutOver]) != null; | |||||
| case Square2: | |||||
| active = getObj(ix, iy, [Plate2, Plate1][game.hueValue], [CanPutOver]) != null; | |||||
| case Square3: | |||||
| if( game.hueValue == 0 ) | |||||
| active = getObj(ix, iy, Plate3, [CanPutOver]) != null || getObj(ix, iy, Steal, [CanPutOver]) != null; | |||||
| else | |||||
| active = getObj(ix, iy, Plate4, [CanPutOver]) != null; | |||||
| case Wings: | |||||
| var obj = getObj(ix, iy, [CanPutOver]); | |||||
| active = obj != null && obj.kind != Steal; | |||||
| default: | |||||
| } | |||||
| if( wasCarried ) { | |||||
| var tx = x * 32, ty = y * 32; | |||||
| var d = hxd.Math.distance(tx - spr.x, ty - spr.y); | |||||
| if( d > 1 ) { | |||||
| spr.x = hxd.Math.lerp(spr.x, tx, 1 - Math.pow(0.7, dt)); | |||||
| spr.y = hxd.Math.lerp(spr.y, ty, 1 - Math.pow(0.7, dt)); | |||||
| return; | |||||
| } | |||||
| wasCarried = false; | |||||
| } | |||||
| super.update(dt); | |||||
| } | |||||
| } | |||||