Joseph Hallenbeck


October 1, 2014

Centipede-RS Dev Log #2

Filed under: Journal,Software Development — Tags: , , — Joseph @ 5:00 pm

Flattr this!

Getting started with Piston can be a little daunted right now. Mostly this is because it’s a project that is still evolving and which has either little documentation or documentation that rapidly becomes wrong. A lot of games that I found made with Piston can no longer be compiled, a lot of example code needs various minor tweaks to get to compile, etc. That said, the two best items that I found where:

Getting Started

The first hurdle in getting Piston to work was getting the SDL2 and GLFW dependencies installed. Cargo does a great job of going out and grabbing everything else, but these two items require you to do it yourself. SDL2 was rather easy and the instructions for it can be found in the Getting Started tutorial (see above). GLFW was a bit more of a pain and I ended up going through a stack overflow question to get it working. If anything, I would just point to the Getting started tutorial to get the initial empty repository set up with cargo and all the dependencies in the Cargo.toml.

My Repository at this Point

At this point my repository looks like this. I began by setting up a new Piston project as detailed in the Getting Started tutorial and from there I copied the code from the piston image example. This was just a nice starting point to ensure that everything is working and that the Rust logo would appear in the window designated.

From there, I began working through the Piston-Mov-Square project and the Getting Started tutorials and religiously commenting every line of the code with what it does. This is just something I picked up in college and a good way to puzzle out foreign code. Even if the comment turns out to be wrong (like it happened in many cases for myself), it at least is a step in manually dealing with the code.

I played around for a while and after I felt confident in the code that I had, I began abstracting it into various data objects and getting down to work. Hopefully my puzzling with help someone else to understand this faster than I.

An Explanation of the Code

Loading Crates

// Load external crates provided via cargo.
extern crate graphics;
extern crate piston;
extern crate sdl2_game_window;
extern crate opengl_graphics;

// Texture is used for images; Gl for accessing OpenGL
use opengl_graphics::{
    Gl,  
};

// For creating a window
use sdl2_game_window::WindowSDL2;

// Stuff from piston.
use piston::{
    EventIterator,                  // Used for the game loop
    EventSettings,                  // Struct used for setting and updates
    WindowSettings,                 // Struct defines window config
    Render,                         // Render Evemt 
};

use piston::graphics::*;
use piston::shader_version::opengl;

We begin by loading all of our various library provided to us by the Piston developers and which we will use for getting our game window to appear on the screen. I have yet to figure out what the #![feature(globs)] lint actually does and if someone does know, I would love to find out since removing it causes everything to break. The rest of the code is just giving us access to various libraries that we will use latter on. I have tried to comment those libraries as best I could since it wasn’t entirely clear what does what.

Config and Main Entry Point

// Config options for the game.
struct GameConfig {
    title: String,
    window_height: u32,
    window_width: u32,
    updates_per_second: u64,
    max_frames_per_second: u64,
    tile_size: uint
}

// Entry point for our game.
fn main() {

    let config = GameConfig {
            title: "Centipede-RS".to_string(),
            window_height: 480,
            window_width: 800,
            updates_per_second: 120,
            max_frames_per_second: 60,
            tile_size: 32,
        };

    // Create and run new game.
    let mut game = Game::new( config );
    game.run();
}

If there is one thing that I know it’s to confine magic numbers. Let them sprout wherever you please and code maintenance becomes a mess. Hence, I have taken the various constants for our game and packaged them up into a GameConfig struct. Right now this struct defines the attributes of our window: title, height, width, frames per second, and tile size. I imagine that this structure will probably grow larger as we begin adding in actors, players, and assets. We will deal with that when the time comes.

I have also created a Game struct (more on it later). The game struct simple takes a GameConfig and returns an instance of itself. Calling run fires off our game loop which loops infinitely or until we kill the process. In essence the Game struct represents and handles the loop. We could leave this in main, but by turning it into a struct we have the option further down the line of moving it out into a module which would leave our main.rs file consisting only of loading Piston, setting the various config items and calling Game.run.

The Game Struct

// Represents the Game Loop
struct Game {
    config: GameConfig
}

impl Game {
    ...
}

I’ve seen this simply called App, but since we are making a game, I think it should be Game. The Game simply holds the game state and runs the game loop. Inside it, I have added several methods via impl: new, run, window, and render. New and run are our public methods which we have already seen. One takes a GameConfig and returns a Game. The other starts the game loop. The remaining methods are just there to run the internals of the loop itself. Let’s walk through each method:

// Returns a new game struct
pub fn new( config: GameConfig ) -> Game {                           

    // Return a new Game
    Game {
        config: config,
    }

}

Game.Run

This one is rather simple. It is a public function (pub fn) named new. We can access it via Game::new(). It takes a GameConfig and returns a Game whose config property is config. I am sure I am mixing a lot of OOP language here, but after years of working in the realm of PHP that’s just how I end up thinking.

// Run the game loop
pub fn run( &mut self ) {

    let mut window = self.window();        
    ...
}  

Run is a little messier it fires off our game loop. It takes a mutable copy of itself which allows us to access it on an instance of Game e.g. game.run(). The first line it calls is to a member function window():

// Returns a window.
fn window( &self ) -> WindowSDL2 {

    // Values for Window Creation
    let window_settings = WindowSettings {
            title: self.config.title.to_string(),
            size: [self.config.window_width, self.config.window_height],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        };

    // Create SDL Window
    WindowSDL2::new(
        opengl::OpenGL_3_2,
        window_settings
    )        
}

This is not a public function, thus when we turn Game into a module it will not be accessible outside of the module file. We are using this essentially as a hidden or private method on Game. The window function is accessible from inside a game object via self, e.g. self.window(). We really only need one window, so this method is only called once at the start of the run method. Window returns a WindowSDL2 which is our back-end we loaded way above at the start for managing our windows. This window takes a WindowSettings struct whose values we pull out of the GameConfig stored in our Game. Either way, it makes a new WindowSDL2 and passes it back to the run method. Now back to our second line of the run method:

// Get Gl
let ref mut gl = Gl::new( opengl::OpenGL_3_2 );

Now this took me a while to figure out. The call to Gl::new() must come after the creation of the WindowSDL2. In an earlier version of this I had the call to create GL after the call to create the Window. The code will compile fine if you create GL first and then the Window, but when you run it you will get a CreateShader error. I only solved this by stumbling upon an IRC log. Anyways, hold on to that gl variable since we’ll be passing it around a lot.

// Create Settings for Game loop
let event_settings = EventSettings {
    updates_per_second: self.config.updates_per_second,
    max_frames_per_second: self.config.max_frames_per_second,
};

Rather boring. We need to create and EventSettings object to pass into our game loop.

// For each e in Event Iterator (whose range is 0 to infinity) 
// e becomes a new Event by passing our window and event settings
for e in EventIterator::new(&mut window, &event_settings) {

    // If e is Render(args) do something, else return ()?
    match e {
        Render(args) => self.render( gl ),
        _ => {},
    } 
}

Here is the magic! The game loop. I really like how this works in Rust. Since iterators can go from 0 to infinite we take advantage of it. The EventIterator takes the window and event_settings variables we set up earlier and returns something (I don’t know what) which is put into e. We then do a match on e to see what was returned. Right now there are only two things that can match: a call to render the screen, or everything else. Looking at some of the example code, I do see that we can catch all different kinds of events — user input, calls to update the game state, etc. but for now we are just concerned with rendering the screen. So we get a render event (Render(args)) and we call our private method render via self.render and pass in our gl variable (I said we would be passing him around a lot).

Game.Render

// Render the game state to the screen.
fn render( &mut self, gl: &mut Gl ) { 
    let width = self.config.window_width;
    let height = self.config.window_height;

    // Get number of columns and rows.
    let tile_size = self.config.tile_size;        
    let num_cols = width as int / tile_size as int;
    let num_rows = height as int / tile_size as int;  
    ...
}

Render simply takes a mutable reference to Gl and paints to our screen. The first two lines just get the window_height and window_width out of our config since we will be using them a lot in this method. Since this is going to be a tiled game we need to know how many columns and rows of tiles we will be drawing. So I calculate that here by dividing the window’s height and width by the tile_size.

// Creates viewport at 0,0 with width and height of window.
gl.viewport(0, 0, width as i32, height as i32);

// graphics::context a new drawing context (think html5)
let c = Context::abs(width as f64, height as f64);

The next two lines in our render call do two important things. First we set our view port to start at the cordinates 0,0 and to extend to the width and height of our window. Second, we get a Context which I like to think as our virtual pen for drawing on our canvas. In fact, the first thing we do is fill the entire canvas with white:

c.rgb(1.0, 1.0, 1.0).draw(gl);

This takes an rgb (red, green, blue) value that sets each to a 100% (or white) and then draws this to our window by calling draw and passing in our old friend gl.

Now let’s have some fun. Just to show that we are indeed drawing on the window, let’s fill the window with 32×32 pixel tiles each one slightly reader than the last. The effect should look like this:

Screenshot of Centipede-RS at Dev-2

We begin by setting our starting red value:

let mut red = 0.01

This needs to be mutable since we will be adding to it with each iteration of our rows.

Second, we loop through each row and each column drawing a red square the size of our tiles:

// Fill screen with red one 32x32 tile at a time.
for row in range(0i, num_rows ) {

    red = red + 0.02;    
    let row_shift: f64 = row as f64 * tile_size as f64;

    for col in range(0i, num_cols ) {

        let col_shift: f64 = col as f64 * tile_size as f64;

        c.square(
            col_shift,
            row_shift,
            tile_size as f64
        ).rgb( red, 0.0, 0.0).draw(gl);                                

    }
}

What does this do? First we are looping through our rows from zero go num_rows (we calculated the number of rows earlier). On each row we adjust our redness slightly this should make each row more red than the last with the first row being fairly dark. Next we calculate row_shift this is simply done my multiplying what row we are on by the size of our tiles. This will be used to tell the context to move down 32 pixels when it gets to row 2, and down 64 pixels when it gets to row 3 and so forth. The inner loop does the same only for our columns. We loop through each column and calculate our col_shift or how far to shift to the right for each column. If I recall correctly this is the most efficient way to loop since the screen paints outwards from your upper-left corner. Finally, we draw our square. The context (c) knows how to draw squares so we pass into it the coordinates of the upper-left corner of our square (col_shift, row_shift), the width of our square as a float (tile_size), instruct the context to fill this square by calling rgb( red, 0.0, 0.0 ). Note, we passed in our red variable so the redness of the tiles should adjust as the red variable does. Last, we draw the square by calling draw and once again passing in gl.

Call cargo build and cargo run and enjoy!


September 26, 2014

Centipede-RS Dev Log #1

Filed under: Journal,Software Development — Tags: , , — Joseph @ 7:23 pm

Flattr this!

A rather rambling design document for my ideas for a Centipede clone that I’m releasing under the MIT license. Following all my reading in Rust it seems like a good idea to have some kind of project to complete. After scrounging about for ideas, I came up with the one of doing an open source centipede clone using Piston. This would be good practice for trying a Rust Ludum Dare next April.

The following is more or less a rambling stream of consciousness design doc for what I’m about to do. I’ll probably follow this up with a series of other entries about the steps and break down of the code as I go.

Concept

A Centipede clone done in Rust using Piston with perhaps some additional flavor.

The core idea of the game is to have a gridded window of size X and Y with a centipede that begins with one segment that grows as the game progresses. The centipede moves continuously in the last cardinal direction specified by the player. As the character moves it encounters various items randomly populated on the screen. Upon contact some effect occurs such as adding an additional segment. If the user comes into contact with itself (such as looping back around on it’s own tail). The game ends or some failure condition occurs.

Objects in the Game

The Game

Well of course it’s an object unto itself. The game represents the game loop.

The Board

The board is 800×480 and divided into 32 pixel squares. At start of the game and at a fixed interval actors are randomly assigned squares on the board.

Centipede

The centipede has the following characteristics:

  • Collection of Segments
  • Who each have a position and sprite
  • Who each have a direction (Each moves in the direction of the segment before it except the head segment which moves in the last direction input by the player).
  • If a segment intercepts another segment it destroys it. The severed segment then becomes bombs.
  • Number of mushrooms eaten (Used as a score)

Actors

Actors specifies an indescriminate number of items placed on the board that the centipede interacts with when it comes into contact with them. The actors need to be able to expand to include new actors with new effects.

  • Sprite
  • Board position
  • An affect

Right now we have two actors: mushrooms and bombs. Mushrooms are placed randomly on the board at a fixed interval. Bombs are segments that have seperated from the centipede. They each have an affect. Mushrooms cause a new segment to be added to the centipede after X mushrooms have been consumed. Bombs cause the game to immediately end.


September 22, 2014

Resources for Learning Rust

Filed under: Journal,Software Development — Joseph @ 11:40 am

Flattr this!

I just started delving into Rust last week with the release of the Rust Guide. In Web Development, I really have moved away from the “bare level” languages of my schooling into the flighty realm of scripting languages. For the most part, I’ve been quite satisfied to leave behind the rigors of memory management and obtuse C linking errors for PHP, JavaScript and Python.

Yet, Rust is the first systems language that really has gotten me excited to sit down and try it out. Maybe get back into the indie game scene (which I have been saying forever).

This post is going to be updated semi-regularly as just a continuing list of Rust resources worth looking into:

Learning the Language

Resources

Community


September 16, 2014

TimeKeeper v0.1.1 Released

Filed under: Journal,Software Development — Joseph @ 11:37 am

Flattr this!

TimeKeeper is a little utility tool that has become both a pet project for testing out new PHP and JavaScript tools as well as a very useful tool that I use every day to keep track of my billable hours, projects and tasks that are completed through out the day. An example of TimeKeeper in action can be found at timekeeper.kynda.net

This week, after a year of dormacy, I updated TimeKeeper to v0.1.1 with a major internal refactoring and improvement in the interface’s “responsiveness.” Major improvements include:

  • The UI is now 100% responsive thanks to a rewrite of all templates to Bootstrap3
  • Libraries now install via bower and composer
  • Moved database configuration into a seperate config.php file, this along with the bower and composer updates makes installing TimeKeeper much easier
  • 100% Documentation of all interfaces and files used by TimeKeeper

Future Plans

TimeKeeper’s direction is still rather vague. This is a useful tool for a single user to keep track of their own time. I am not yet sure if I want to keep it focused on being a planning tool for a single user or to expand TimeKeeper into a team-based tool.

The single biggest issue with TimeKeeper is that it does not provide a password-protected user log in which means that it cannot be public-facing or at least ends up relying on apache for user-login.

v0.2.0 RoadMap

For v0.2.0, which will be released “whenever,” I plan on adding the following features to TimeKeeper:

  • Single-User Password Log In (so the site can be public-facing)
  • A Reports table that generates a variety of charts analyzing the filtered time frame including: break down of 100% time spent per project or billable hours; daily break down showing hours worked and whether they went over or under 40 hours; Perhaps a monthly report as well.
  • 100% Test coverage

August 25, 2014

Sketch Journal #11 – Native Plants

Filed under: Journal,Sketch Journal — Joseph @ 8:49 am

Flattr this!

The following sketches are from my field notebook. They were done while taking a native plants class with Klara Varga in Jackson Hole. In particular, these plants were all found growing along the roadway through the Elk Refuge.

Arrowleaf Balsam Root
Aster
Basin Wild Rye
Choke Cherry
Fireweed
Fringed Sage Brush
Goldenrod
Lupin
Lupin
Rabbit Brush
Rose Hips
Smooth Brom
Tri-Tipped Sage Brush


June 3, 2014

Photo Journal #11 – North Juniper Hill

Filed under: Journal,Photography — Joseph @ 10:37 pm

Flattr this!

North of the open dunes is North Juniper Hill, the tallest of the St. Anthony Sand dunes at 6,625 ft and a rise of roughly 1,000 feet above the surrounding fields. It’s sandy all the way up to the top. We took two days backpacking, this photo is a cropping of a 360 degree panorama of 21 stitched images.

North Juniper Hill

North Juniper Hill

Model: Nikon D80 /w Nikon 35mm f/1.8 AF-S DX Shutter: 1/320 sec
F-Stop: f/9
ISO: 250
Focal Length: 35mm
Lighting: None
Stitches: 21


May 30, 2014

Photo Journal #10 – St. Anthony Sand Dunes

Filed under: Journal,Photography — Joseph @ 10:36 pm

Flattr this!

The St. Anthony Sand Dunes west of St. Anthony, Idaho are perhaps one of the hidden gems out here. It took us almost a year to bother checking them out due to all the talk of ATV use. It is true, the dunes are infested with ATV droning on, but by late evening it seems like they die down and leave a little peace and quite. The dunes themselves are quite impressive, we thought we would be seeing some small dunes or patches of sand, instead we found massive open dunes rising 300 feet above the nearby potato fields. The one on the right measures out at about 320 feet and took crawling on our hands and knees to ascend to the peak.

St. Anthony Sand Dunes

St. Anthony Sand Dunes

Model: Nikon D80 /w Nikon 35mm f/1.8 AF-S DX
Shutter: 1/320 sec F-Stop: f/9
ISO: 250
Focal Length: 35mm
Lighting: None
Stitches: 14


January 2, 2014

2013 In Review

Filed under: Journal — Joseph @ 12:34 am

Flattr this!

2013 In Review

In the spirit of the season, I hope to do a little navel gazing. So, if reading through a pile of narcissistic schlock wherein I attempt to showcase just how amazing my life is, read on. Otherwise, it would be best to skip this. Honestly, I would not blame you at all.

Professionally this year has held quite a roller coaster of changes. I changed firms, moving over to 44 Interactive. This brought with it a much wider range of responsibilities and opened doors into expanding my skills into a avenues that I had not yet explored.

Bogun

At the new firm, I switched to developing 100% on Linux (Ubuntu and CentOS). It was a rocky first month, but now I would never switch back to working in the Windows environment. I oversaw a major revision of production servers at the new firm, getting things PCI compliant and automating a lot of processes using Python and Bash – two languages that I picked up last spring.

I picked up a lot of new tools with the move as well. I started doing regular development in Code Igniter, expanded my knowledge of Lemonstand, and wrote an internal toolset using Silex. I modernized my front-end skills – working with LESS, HTML5, and building increasingly more complex ajax sites with a much more solid understanding of modular/pseudo-classical JavaScript.

I worked on our custom CMS, normalizing it’s database structures, introducing a number of design patterns to enhance re-usability, getting it into a repository, and wrangling out a lot of cruft as it became a leaner, more focused application.

As for personal projects, I rewrote the templates for my portfolio and “culture” blogs, moved them onto my own VPN, started hosting my own e-mail server, and got onto Linkedin and back into regularly blogging. I started to revise my old coursework in C and daydreaming of making some small game projects in C/Python.

2013 saw me move four times. I started with a move to a new house in Sioux Falls on the first of the year. I split my time at that house with traveling to a second rental in Hullet, Wyoming. In May, the rental in Hullet went away and I began dividing my time between Sioux Falls and Island Park, Idaho (and later on another move down the mountain to Ashton, Idaho where I began to telecommute 100% of the time).

All this moving gave me quite an incentive to cut down on my possessions. It is amazing what a couple years of sedentary life can do for property. When I moved to Sioux Falls a couple years past, all I owned fit in my trailer. This year, it took me six loads to haul it all out to Idaho.

Oak Table

The new house, in Sioux Falls, lacked counter space, so I took this as a challenge to take up carpentry. I built a fine Oak butcher-block style table that now resides in my home office as a standing desk.

In Sioux Falls, I made it to figure drawing nearly every week that I was in town, amassing quite a collection of drawings and sketches.

In Idaho, I explored Craters of the Moon, backpacked the Jedediah Smith Wilderness Area, dipped my toes in Bear Lake, explored half a dozen different day hikes throughout the area, and am now regularly snow shoeing along old rail road right of ways. All of this resulting in a pile of nature photographs that I am just now starting to compile and process.

I had a bit of a health scare in Idaho. A false appendicitis lead to all kinds of new experiences with the American medical system. A sciatica afterwards left me crippled for nearly a month. In the end, I found myself resolved to get back into shape by switching to a standing desk and waking early for a heavy dose of aerobics before work.

Through the year, I discovered Black Books, read Chomsky, the translated works of Yoshitiro Tatsumi, Lovecraft’s At the Mountains of Madness, re-visited Kerouac, and the poetry of Allen Ginsberg. I played Fez and Shelter. I began the Prince of Persia series and Zelda Twilight Princess.

I made it a point to try to put 30 minutes each day into reading a text about computer science, be it a volume on patterns for Python, pointer arithmetic in C, or artfully designing databases. I feel that I have reached the point where I just “get” it when it comes to development. I can sit and read across the field and generally understand the content and feel confident that I can apply the techniques in the texts without misinterpreting them or misapplying them.

2014 In Resolution

So, I suppose now that I have sat down and covered the many highlights of the last year I should address myself to the upcoming new year and the good things that I want to bring about.

I am going to keep reading. I am going to keep putting that 30 minutes of personal development in CS each day, but I also should set more time aside to just sit down and game. Two hours for two nights a week and maybe a couple binges – lets say 160 hours by the end of the year which would put me through four decently sized games. Now that we’re on the new console generation it is time to pick up a PS3 and the backlog of exclusive titles along with all the Wii titles that I let slip.

I hope to pick up a role playing group for one evening of the week, and challenging myself to finally break down and go to Friday-Night Magic.

I want to challenge myself to bike to Driggs and back this summer (80 Miles). I would also like to backpack Targhee Peak via Coffin lakes, challenge myself to complete the backpacking trip to Jedediah Smith Wilderness Area, snow shoe to Warm River Cabin, canoe Warm River to Snake River, and spend a week backpacking in Escalante.

The big thing is going to be the projects for this next year. Items, I really am excited to see. I just have been so busy the last couple of years to really focus any of my attention on some personal projects other than the occasional essay.

Pecunia

I’ve already addressed Pecunia in this blog. This is my open-source financial planner/budget maker built around Silex (although, I am now leaning towards Laraval4). I envision this as a multi-user website that will allow users to create budgets, log expenses, and keep track of their personal finances. Oh, and it will be completely open-source and available for review on my BitBucket account. (Personal Deadline: Spring 2014)

PyGame

This is a much more vague idea, because I just have not sat down to flesh it out. I want to sit down and make a small collection of old-school arcade clones in Python, and slowly work my way up to creating a nicely polished 2D platformer. (Personal Deadline: 2015)

The Weird Tale

I have this short story that has been in the works for three years. In my day planner, it’s noted down as “the weird tale.” It’s a Lovecraftian tale of monsters and madness. I really need to finish it. (Personal Deadline: Rough Draft Summer 2014, Final Draft Fall 2014)

Blog

It’s nice to be blogging regularly again. This year, I aim for 12 solid articles.

Architectural Drawing

I have spent the last three years working on figure drawing. It’s time to return to architectural drawing. Once it gets nice outside, I aim to take the easel outside and start sketching out each of the buildings in this small town.

Photo Showcase

An annual addition to the list, since I still haven’t done it. I really need to get a gallery showing put together of my photos. The issue is always that by the time I have a good enough collection of photos for a given place, I move. (Personal Deadline: Fall 2014)

NaNoWriMo

I’ve been off NaNoWriMo since somewhere around 2007. It’s time to get back in there and write a new one. So this year, let’s be serious and put it on the list.

Inevitably, more projects will probably arise in my mind through the year, and I will address them as they appear, but for now that’s the whole list.


September 16, 2013

NextGEN Gallery 2.0.21 Lightbox Fix

Filed under: Journal — Tags: , , , — Joseph @ 9:00 am

Flattr this!

I decided to share my fix for lightboxing in NextGEN Gallery 2.0.21. This version of the WordPress plugin for some odd reason breaks support for lightboxing the gallery images (that is having the gallery image “pop out” in front of the page when clicked).

This fix does not modify the NextGEN gallery itself so we can easily revert to using NextGEN’s lightboxing whenever it gets fixed.

Follow these steps:

1. Turn off NextGEN Lightbox Effect

Log into the dashboard of your WordPress installation and navigate to Gallery >> Other Options and select Lightbox Effects. There select from the drop down No lightbox

2. Install Lightbox 2 v2.6

It is important to have the most up-to-date version of Lightbox because of compatiblity issues with jQuery 1.10. Go to the Lightbox 2 website and download the latest version of lightbox, unzip the download and upload the resulting directory into your theme’s directory on your server (it should be in /wp-content/themes/).

3. Update header.php To Load Lightbox 2

Now from the WordPress dashboard select Appearance >> Editor >> header.php. For those of you without programming experience this might seem arcane but follow along. Between the <head> and </head> tags include the following lines of code:

<style type="text/css" media="screen">
        @import url( '<?= get_theme_root_uri() ?>/THEME/lightbox/css/lightbox.css' );
</style>
<script 
  type="text/javascript" 
  src="<?= get_theme_root_uri() ?>/THEME/lightbox/js/lightbox-2.6.min.js">
</script>        

Where THEME is the name of your current WordPress theme.

4. Add Custom Script to Your Footer

There is two ways of going about this. First navigate this time to `Apperance >> Editor >> footer.php. We can either append the javascript directly to the end of this file, or (the better solution) you could create an external javascript file and load it.

To do the latter, you simply create a file named lightfix.js and paste the script below minus the <script> and </script> tags. Then include it in your file the same way that you included lightbox-2.6.min.js above only this time append the include to the end of the footer.php.

If you want to just put the script directly in footer.php just copy the text below directly into the file:

<script>
( function( $, images ) {
  $(img).each( function() {
    if( $(this).parent().is('a') {
      $(this).parent().attr('rel', 'lightbox');
    }
  }
})( jQuery, '.storycontent img');
</script>

You might need to modify .storycontent img to fit your own theme. This script selects all the img html elements in the div with a class name storycontent it then loops through each of these images and if they are contained inside an anchor tag then it transforms that image into a lightbox. Since each picture in the NextGEN gallery is wrapped in an anchor tag linking to the image source this should automatically work alongside Lightbox 2 to return the lightbox functionality to our gallery.


September 14, 2013

New Wind-Up Post: Fez

Filed under: Journal — Joseph @ 11:22 pm

Flattr this!

Fez Screenshot

I have a new post over on the Wind-Up Culture Blog concerning the the extraordinary polish of Fez. Right now, I’m at 82% of Fez completed and the game continues to blow my mind away with the complexity of this indie title.




« Newer PostsOlder Posts »

Copyright 2011 - 2017 Joseph Hallenbeck Powered by WordPress