Posts about Tutorials


Angry Circles


imageFor the next couple of weeks I though we might explore the rudiments of physics simulators and I was inspired by the excellent tutorials from Peter Collingridge on the topic. We have covered all the basic python tools we need already, so I think we can leap in with a fairly functional demo which will allow you to fling some 2D circular shapes (we’re calling them particles) around using the mouse. The particle implementation is also an excellent use of the concept of Classes we discussed a few weeks ago. In the code below you can see how we group together all the data and behaviour (the functions or methods) of a particle in one piece of code that defines a Particle class and then create lots of ‘instances’ of particles – each has the same structure (making all the management code much easier) but they all maintain own specific data values - positions, speeds and directions etc. This is perhaps the simplest (but still very powerful) benefit of using classes – we will come onto other benefits in due course.

Take a look at the code below. At the bottom you should by now recognise the absolutely standard game loop – with the usual input->update->draw cycle. I hope you will see it is surprisingly short and very readable! This is a good indication of the well structured code above. In the middle of the code, after we define a couple of helper functions, is the definition of the class (make sure you get your indenting right here – the class’ functions must be indented inside the class level. The interesting aspects of the maths I will cover in tonight’s session – but it all comes down to some very simple sin, cos, tan usage and good ol’ Pythagoras.

import pygameimport randomimport mathbackground_colour = (255,255,255)(width, height) = (400, 400)drag = 0.999elasticity = 0.75gravity = (math.pi, 0.2)def addVectors(vector1, vector2):angle1 = vector1[0]length1 = vector1[1]angle2 = vector2[0]length2 = vector2[1]x = math.sin(angle1) * length1 + math.sin(angle2) * length2y = math.cos(angle1) * length1 + math.cos(angle2) * length2angle = 0.5 * math.pi - math.atan2(y, x)length = math.hypot(x, y)return (angle, length)def findParticle(particles, x, y):for p in particles:if math.hypot(p.x-x, p.y-y) <= p.size:return preturn Noneclass Particle():def __init__(self, x_y, size):self.x = x_y[0]self.y = x_y[1]self.size = sizeself.colour = (0, 0, 255)self.thickness = 1self.speed = 0self.angle = 0def display(self):pygame.draw.circle(screen, self.colour, (int(self.x), int(self.y)), self.size, self.thickness)def move(self):(self.angle, self.speed) = addVectors((self.angle, self.speed), gravity)self.x += math.sin(self.angle) * self.speedself.y -= math.cos(self.angle) * self.speedself.speed *= dragdef bounce(self):if self.x > width - self.size:self.x = 2*(width - self.size) - self.xself.angle = - self.angleself.speed *= elasticityelif self.x < self.size:self.x = 2*self.size - self.xself.angle = - self.angleself.speed *= elasticityif self.y > height - self.size:self.y = 2*(height - self.size) - self.yself.angle = math.pi - self.angleself.speed *= elasticityelif self.y < self.size:self.y = 2*self.size - self.yself.angle = math.pi - self.angleself.speed *= elasticityscreen = pygame.display.set_mode((width, height))pygame.display.set_caption('Angry Circles')number_of_particles = 3my_particles = []for n in range(number_of_particles):size = random.randint(10, 20)x = random.randint(size, width-size)y = random.randint(size, height-size)particle = Particle((x, y), size)particle.speed = random.random()particle.angle = random.uniform(0, math.pi*2)my_particles.append(particle)clock = pygame.time.Clock()selected_particle = Nonerunning = Truewhile running:clock.tick(20)for event in pygame.event.get():if event.type == pygame.QUIT:running = Falseelif event.type == pygame.MOUSEBUTTONDOWN:(mouseX, mouseY) = pygame.mouse.get_pos()selected_particle = findParticle(my_particles, mouseX, mouseY)elif event.type == pygame.MOUSEBUTTONUP:selected_particle = Noneif selected_particle:(mouseX, mouseY) = pygame.mouse.get_pos()dx = mouseX - selected_particle.xdy = mouseY - selected_particle.yselected_particle.angle = 0.5*math.pi + math.atan2(dy, dx)selected_particle.speed = math.hypot(dx, dy) * 0.1screen.fill(background_colour)for particle in my_particles:particle.move()particle.bounce()particle.display()pygame.display.flip()

Zombie Text Adventure!


This week we’ll be looking at a different sort of game – the typed text adventure. I’ve tidied up and simplified  ‘Zombies in Kenilworth’ (for those who have seen it previously) so that you will be able to reuse the core code to create your own text adventures.

My version has just 6 locations and 3 in-game objects that must be collected and used to escape from the zombie apocalypse that engulfed the computer lab. I am sure that you will be able to come up with some significant enhancements – if not entirely your own take on the text adventure genre.

For those of you who like to do the typing, here it is in all its glory. I’ve marked the section CUSTOMISE THE CODE HERE where you can replace my Zombie adventure with one of your own. Simply plan our a map of locations and their connections (exits). Then decide which exits will block progress by being locked, and add in a selection of cryptic objects which must be collected, taken to the locked locations and used in order for the player to progress through your map.

See you later.

 

def 
AddGameLocation(id, name, description):
global locations_map
locations_map[id] = {
"Name" : name, "Description" : description}
locations_map[id][
"Exits"] = {}
return
 

def AddGameObject(name, description, location_id, use_location_id, use_target, use_message):
global object_list
object_list[name] = {
"Description" : description , "Location" : location_id, "UseLocation" : use_location_id, "UseTarget" : use_target, "UseMessage" : use_message}
return
 

def AddUnlockableGameLocationExit(location_id, exit_name, location_exit_id, unlocked_description, locked_description = "none"):
global locations_map

if exit_name not in locations_map[location_id]["Exits"]:
if locked_description != "none":
locations_map[location_id][
"Exits"][exit_name] = {"ExitLocation" : location_exit_id, "Status" : "locked"}
else:
locations_map[location_id][
"Exits"][exit_name] = {"ExitLocation" : location_exit_id, "Status" : "unlocked"}
locations_map[location_id][
"Exits"][exit_name]["Descriptions"] = {}


locations_map[location_id][
"Exits"][exit_name]["Descriptions"]["unlocked"] = unlocked_description
if 
locked_description !=
"none"
:
locations_map[location_id][
"Exits"
][exit_name][
"Descriptions"
][
"locked"
] = locked_description
return
 

def UseExit(exit_name):
global current_location_name
global locations_map

exit = locations_map[current_location_name][
"Exits"][exit_name]

if exit["Status"] == "unlocked":
# if this exit is unlocked then we allow the change of location
current_location_name = exit["ExitLocation"]
print("You move to " + locations_map[current_location_name]["Name"])
return True
else
:
# otherwise print this exit's description according to its current status
print("")
print(exit["Descriptions"][exit["Status"]])
print("")
return False
 


def UseObject(object_name):
global object_list
global current_location_name
global locations_map

# Return and message and error if the object is
# not in our object dictionary
if object_name not in object_list:
print("I don't know about this object")
return False
 

# Check if the player has the object (its location is 'player'
object = object_list[object_name]
if object["Location"] != "player":
print("You do not have that")
return False
 

# Check if the object is intended to be used here
if object["UseLocation"] != current_location_name:
print("You cannot use that here")
return False
 

# Get the current game location dictionary entry
game_location = locations_map[current_location_name]

# go through all the items in this location's exit dictionary
for exit_key in game_location["Exits"]:
# Check if one of the exits matches the objects UseTarget
if game_location["Exits"][exit_key]["ExitLocation"] == object["UseTarget"]:
# Unlock the exit
game_location["Exits"][exit_key]["Status"] = "unlocked"
# Print the Object's UseMessage
print(object["UseMessage"])
# Call the UseExit function to move the player to the new location
UseExit(exit_key)
return True


# if we get here we couldn't find an exit to match the use_target
# specified in this object - probably a mistake!
print
(
"This object appears to have no purpose"
)
return False
 

def Move(direction):
global current_location_name
if direction in locations_map[current_location_name]["Exits"]:
# location_exit = locations_map[current_location_name]["Exits"][direction]
if UseExit(direction):
Look()
else:
print("You cannot go that way")


def
Look():
global 
current_location_name
global 
object_list

print
(
"You are in " 
+ locations_map[current_location_name][
"Description"
])
print
(
""
)

first_item =
True
for
object_key
in 
object_list:
if 
object_list[object_key][
"Location"
] == current_location_name:
if 
first_item ==
True
:
print
(
"You can see:"
)
first_item =
False
print
(object_key +
" - " 
+ object_list[object_key][
"Description"
])

print
(
""
)

first_item =
True
game_location = locations_map[current_location_name]
for 
exit_key
in 
game_location[
"Exits"
]:
if 
first_item :
print
(
"There are exits to the:"
)
first_item =
False
print
(exit_key +
" - " 
+ game_location[
"Exits"
][exit_key][
"ExitLocation"
])
print
(
""
)


def
Take(object_name):
for 
object_key
in 
object_list:
object = object_list[object_key]
if 
object[
"Location"
] == current_location_name
and 
object_key == object_name:
object[
"Location"
] = "player"
print
(
"You take the " 
+ object_name)
return

print(
"You cannot see that here"
)


def
ShowHelp():
print
(
"Commands available:"
)
print
(
"look                      - Describes where you are"
)
print
(
"north, south, east, west  - Moves you in a direction"
)
print
(
"help                      - Prints this help"
)
print
(
"take [Object]             - Take an object with you"
)
print
(
"use  [Object]             - Use an object at this location"
)
print
(
""
)


# ============ CUSTOMISE THE CODE HERE ==========
 

# Edit this function to set the start location and intro text
def ResetGame():
global current_location_name
current_location_name =
'lab'
print(" ______________________________ ")
print("| == Zombies in Kenilworth == |")
print("| A GCC Text Adventure |")
print("|______________________________|")
print("")
print("You were at the Computer Club when suddenly someone shouted 'Zombies!!'")
print("There was panic. You hit your head...")
print("and that was the last thing you can remember")
print("")



# Your game map is made up of game locations.
# Add each one using AddGameLocation(id, name, description):
# id = unique name used by the game to identify this location
# name = printable name shown to the player
# description = long description used as part of the reponse to a 'look' by the player
 
AddGameLocation("lab", "the computer lab", "a familiar room where GCC is usually held. It is still full of computers, but they have all been smashed; As have the tables and chairs.")
AddGameLocation(
"cupboard", "the stock cupboard", "a small cupboard where the teacher normally keeps stationary and lesson equipment.")
AddGameLocation(
"shelf", "the dusty shelf", "a small shelf, covered in dust. Evidently nobody has looked up here for quite a while.")
AddGameLocation(
"corridor", "the corridor", "a normally bustling thoroughfare, but it is eerily silent.")
AddGameLocation(
"foyer", "the foyer", "the entrance to lower school and your way out!")


# This location - 'escape' is special and triggers the end of the game
AddGameLocation(
"escape"
,
"the outside world!"
,
"the outside world again. You breathe the fresh air... but then you hear the sound of moaning. Time to run!"
)

# Now connect up your game locations with exits - if you add an extra 'locked' description then the exit
# AddUnlockableGameLocationExit(location_id, exit_name, location_exit_id, unlocked_description, locked_description = "none"):
# location_id = the unique location name to which this exit belongs
# exit_name = the name used by the player to 'Use' this exit - usually a direction, so could be 'up' or 'down' etc.
# location_exit_id = the unique location name of the location to which this exit leads
# unlocked_description = the description used when the location is unlocked (the default)
# (optional) locked_description = can be left off, the description used when the location is locked. Specifying this will also lock the location
AddUnlockableGameLocationExit(
"lab"
,
"north"
,
"corridor"
,
"you go through to the corridor"
,
"the door is locked."
)
AddUnlockableGameLocationExit(
"lab"
,
"east"
,
"cupboard"
,
"you go into the cupboard"
)
AddUnlockableGameLocationExit(
"cupboard"
,
"west"
,
"lab"
,
"you go through to the computer lab"
)
AddUnlockableGameLocationExit(
"cupboard"
,
"east"
,
"shelf"
,
"you climb up to the shelf"
,
"You can see a shiny object, but the shelf is too high to reach"
)
AddUnlockableGameLocationExit(
"shelf"
,
"west"
,
"cupboard"
,
"you climb back down to the stock cupboard"
)
AddUnlockableGameLocationExit(
"corridor"
,
"south"
,
"lab"
,
"you return to the computer lab"
)
AddUnlockableGameLocationExit(
"corridor"
,
"north"
,
"foyer"
,
"you go through to the foyer"
)
AddUnlockableGameLocationExit(
"foyer"
,
"south"
,
"corridor"
,
"you return to the corridor"
)
AddUnlockableGameLocationExit(
"foyer"
,
"east"
,
"escape"
,
"you walk passed the zombie, who is too busy eating to notice you"
,
"You can see your way out, but a zombie blocks the way"
)
AddUnlockableGameLocationExit(
"escape"
,
"west"
,
"foyer"
,
"you return to the foyer"
)

# Finally add the game objects that will be used to unlock the matching exits
# AddGameObject(name, description, location_id, use_location_id, use_target, use_message)
# name = the object's name (must be unique within the game)
# description = used to describe the object to the player. Should *hint* at its potential use
# location_id = where this object will be found
# use_location_id = where this object should be used
# use_target = the name of the location exit id that it will unlock at the use location
# use_message = the printed message given when the object is successfully used
AddGameObject(
"box"
,
"a small but sturdy box"
,
"lab"
,
"cupboard"
,
"shelf"
,
"You stand on the wooden box. Now you can reach the high shelf"
)
AddGameObject(
"key"
,
"a small key like the ones the teachers carry"
,
"shelf"
,
"lab"
,
"corridor"
,
"The key fits the locked door perfectly. The lock clicks and the door swings open..."
)
AddGameObject(
"brains"
,
"a glob of partially consumed brains. You think that they might once have been Edward's..."
,
"lab"
,
"foyer"
,
"escape"
,
"The zombie greedily grabs the brains and starts munching. He seems entirely distracted."
)
 
# =================================================
 

# Here are the global variables which
# can be used by all the functions and objects
# we have created
current_location_name = ''
game_running = True
locations_map = {}
object_list = {}


# This prints the title block when the program first runs
 
ResetGame()
ShowHelp()


# Main game loop
while
game_running:
# wait for input and store it in 'command'
command =
input
(locations_map[current_location_name][
"Name"
] +
" >>"
)


# Use lower() to make everything lower case before
# doing a match test, otherwise 'Help' would not be recognised as 'help'
command = command.lower()


# split 'command' wherever there is a space to make a list of 'commands'
commands = command.split(" ")


# Call a function if the first command (position [0] in the list)
# is one we know.
if commands[0] == "look":
Look()

elif commands[0] == "help":
ShowHelp()

elif commands[0] == "north" or commands[0] == "south" or commands[0] == "east" or commands[0] == "west":
Move(commands[
0])

elif commands[0] == "take":
if len(commands) > 1:
Take(commands[
1])
else:
print("Take what?")

elif commands[0] == "use":
if len(commands) > 1:
UseObject(commands[
1])
else:
print("Use what?")

else:
print("I don't know that word. Try again.")
ShowHelp()


if 
current_location_name ==
"escape"
:
again =
input
(
"Play Again? (Y/N) >>"
)
again = again.lower()
if 
again !=
"y"
:
game_running =
False
else
:
ResetGame()

What a state to get into…


This week we are going to be adding our game state code to the basic (and reusable) game loop code from last week. The structure of the code is going to be very simple. In the Update function we are going to choose a particular block of code according to current game state (using the If…, Elif…, Elif…, Else… conditional structure you have encountered previously). Each block of code will check input and game data and simply change the current game state to a new one if necessary. Essentially all of our game logic will be captured in this function – although we will create some other ‘helper’ functions to complete repetitive tasks without having to copy and paste code (if you find yourself doing this, it is a sure sign that your code needs a better structure – time to ‘refactor’).

The Draw code can now be extremely simple. It will just dumbly draw items according to the current game state.

image

The diagram above shows a simple design of the 7 new game states we need (not including the existing ‘Quit’ state) and the events we will be looking for in the Update function to trigger transitions between the states. When you design a game you should definitely have something like this diagram early on to help you plan your project – pretty much all games have some sort of state structure within them.

In our simple game, the transition events will either be mouse clicks from the player, or internal timers. The timers will determine how long it takes for Sam to draw his guns, how quickly he fires and also the duration of the animation of firing (essentially how long we remain in the ‘Fire’ game state, where we blit the gun flashes, before moving to the ‘Lose’ game state, where we don’t).

Code Snippets

OK well to be honest that is the hard bit done, the rest is just typing Winking smile

Update

The update function captures the diagram above in code form:

def Update():
global current_keys, last_keys, current_mouse, last_mouse, \
gamestate, time_to_draw, time_to_fire, total_time

last_keys = current_keys
current_keys = pygame.key.get_pressed()

last_mouse = current_mouse
current_mouse = pygame.mouse.get_pressed()

elapsed_ms = pygame.time.Clock().tick(
30)
total_time = total_time + elapsed_ms

if gamestate == "Start":
if LeftMouseClicked():
gamestate =
"Ready"
elif
gamestate == "Ready":
if total_time > time_to_draw:
total_time =
0
gamestate = "Draw"
elif
LeftMouseClicked():
gamestate =
"TooEarly"
elif
gamestate == "Draw":
if total_time > time_to_fire:
total_time =
0
gamestate = "Fire"
if
LeftMouseClicked():
gamestate =
"Win"
elif
gamestate == "Fire":
gamestate =
"Lose"
elif
gamestate == "TooEarly":
if LeftMouseClicked():
Reset()
gamestate =
"Start"
elif
gamestate == "Win":
if LeftMouseClicked():
Reset()
gamestate =
"Start"
elif
gamestate == "Lose":
if LeftMouseClicked():
Reset()
gamestate =
"Start"
else
:
print("Update Error: Unknown gamestate")

Draw

The Draw function simply draws the screen according to the current game state:

def Draw():
global background_surface, screen, sam_surface_set

screen.blit(background_surface, (
0,0))

if gamestate == "Start":
DrawTitle(
"Click to Start")
elif gamestate == "Ready":
DrawSam(
"Ready")
elif gamestate == "Draw":
DrawSam(
"Draw")
elif gamestate == "Fire":
DrawSam(
"Fire")
elif gamestate == "TooEarly":
DrawTitle(
"You'll hang for this!")
DrawSam(
"Innocent")
elif gamestate == "Win":
DrawTitle(
"Got me you varmint")
DrawSam(
"Shot")
elif gamestate == "Lose":
DrawTitle(
"Take that!")
DrawSam(
"Ready")
else:
print("Draw Error: Unknown gamestate")

pygame.display.flip()
return

Additional Helper Functions

To avoid the noob error of cutting and pasting repeated code, and to make the code easier to understand and manage, several additional helper functions are handy to add. The first checks for a mouse click by seeing of the left mouse button is newly pressed – i.e. it is pressed this time around the game loop, but not last time – this prevents a single mouse click triggering loads of mouse click transitions in one go.

def LeftMouseClicked():
global current_mouse, last_mouse
return current_mouse[0] and not last_mouse[0]

Note that this function returns the boolean True or False so you can use it anywhere that python needs a boolean. This is an example of a function with a return type and they are very handy things!

We also can draw a nice centred bit of large text using the DrawTitle function:

def DrawTitle(string):
global big_font, screen
text = big_font.render(string,
1, (255, 128, 128))
shadow = big_font.render(string,
1, (0, 0, 0))
textpos = text.get_rect()
textpos.centerx = screen.get_rect().centerx
shadowpos = shadow.get_rect()
shadowpos.center = (textpos.centerx +
2, textpos.centery + 2)
screen.blit(shadow, shadowpos)
screen.blit(text, textpos)

Finally, Sam himself is represented by a set of surfaces – different ones for the game states. To store these I use a dictionary structure to allow us to get the surface we are after using a nice, friendly, string name. I create this dictionary just once inside the Init function, along with the global fonts used above:

# Load the other sprite images
sam_surface_set = { \
"Ready" : pygame.image.load("images/YosemiteSamReady.png").convert_alpha(), \
"Draw" : pygame.image.load("images/YosemiteSamAim.png").convert_alpha(), \
"Fire" : pygame.image.load("images/YosemiteSamFire.png").convert_alpha(), \
"Innocent" : pygame.image.load("images/YosemiteSamInnocent.png").convert_alpha(), \
"Shot" : pygame.image.load("images/YosemiteSamShot.png").convert_alpha() \
}


# Create some reusable fonts
big_font = pygame.font.Font(None, 72)
little_font = pygame.font.Font(
None, 36)

then I use it inside a handy DrawSam function that will draw the correct Sam according to the name that you pass in:

def DrawSam(state_string):
global screen
sam_surface = sam_surface_set[state_string]
target = sam_surface.get_rect()
target.center = screen.get_rect().center
screen.blit(sam_surface, target)

That’s it! In your version of the game try adding some new game states or swap out the images for a different theme of game. Perhaps a high score screen showing the fastest reaction time achieved in this session of the game?

Shootout – Session 1


imageThis week we will be starting a new game – Shootout. It is essentially a reaction time test, but using a western gunfight theme. Yosemite Sam will draw and fire and the player must shoot him after he draws, but before he fires. If you shoot him before he draws then you will surely hang for killing an innocent man, but if you wait too long…

To tackle this game we will be looking at a really common pattern in computer programming – the finite state machine (or FSM). This is a really useful way of breaking down the computational logic required for many tasks you will encounter.

But before we get onto that, we need to create the usual basic game framework – a loop which cycles updating our game data and drawing the screen. As previously we will break this down into functions that each deal with a specific aspect of the game.

In a new python file, import the libraries we are going to need – pygame, sys and random.

import sys, pygame, random

Now we need to create our function structure.

Init

This function completes all the one-time initialisation of the game. Things that are done once, and only once, when our program is first run – such as creating the game screen window and loading the game assets into memory.

def Init():
global screen, current_keys, current_mouse, \
background_surface, gamestate, \
big_font, little_font


# Initialise pygame - must always be done first
pygame.init()

gamestate =
"Start"


# Set the screen size using background image size
background_surface = pygame.image.load("images/Background.png")
screen_size = background_surface.get_size()
screen = pygame.display.set_mode(screen_size)


# Convert the surfaces according to the screen bitdepths
# This will dramatically speed up blitting later
background_surface = background_surface.convert()


# Load a big and little font
big_font = pygame.font.Font(None, 72)
little_font = pygame.font.Font(
None, 36)


# Initialise our pressed key list
current_keys = pygame.key.get_pressed()
current_mouse = pygame.mouse.get_pressed()

Reset

This function resets all the properties of our game for each go. Having started the game up, we expect the player to have several go’s and so this function will be called lots of times. Since we haven’t started to create our game yet, this function is empty and we can just use the return keyword. As the game develops, we will add more code here.

def Reset():
return

GameLoop

The main process of repeating the update and draw cycle. This function will only complete and return when we ‘quit’ the game – this is triggered by setting the gamestate variable to “Quit”.

def GameLoop():
global gamestate
while gamestate is not "Quit":
for event in pygame.event.get():
if event.type == pygame.QUIT:
gamestate =
"Quit"



Update()
Draw()


# If we get here, we should quit
sys.exit()

Update

This function processes all the changes to the game data in response to time, user input or other events.

def Update():
global current_keys, last_keys, current_mouse, last_mouse
last_keys = current_keys
current_keys = pygame.key.get_pressed()

last_mouse = current_mouse
current_mouse = pygame.mouse.get_pressed()
elapsed_ms = pygame.time.Clock().tick(30)

Draw

This function constructs and draws our screen. As you create more sophisticated game loops, you will find that you will usually call the update and draw functions at different rates so keeping this work logically separate is a good habit to get into.

Call the functions

Finally we need to actually call these functions (remember, they are only defined so far and so won’t actually run), so at the bottom of your file add your calls.

Init()
Reset()
GameLoop()

Now you should be able to F5 and see your window created according to the background image and the loop should run until you close the window. Essentially, this set of code is the basis of any game you may wish to start, so it might be a good idea to keep a copy of it somewhere so you can reuse it easily in the future. Next week we’ll discuss how to structure and begin adding our game logic to this framework.

Minecraft Modding in Java


What is needed?

  • JRE
  • JDK
  • IDE (Netbeans)
  • MINECRAFT FORGE (for 1.5.2)
  • FML libs for 1.5
  • Some know-how…

Install

  • Install JRE, JDK, IDE
  • Set PATH to include JRE & JDK
  • Unzip Minecraft Forge
  • Run Install.cmd while online
    • Downloads more stuff
    • Creates MCP (Mod Coder Pack)
    • Creates FML (Forge Mod Loader)
    • Decompiles and patches minecraft

• Unzip fml libs (into mcp\lib) [on 1.5.2]

• Run Install.cmd again! [on 1.5.2]

Prepare to program

  • Set up IDE
    • Edit project workspace settings (MCP_LOC)
    • Import project workspace
    • Shuffle which libs are used in preference in project
    • Tell game where to find native libs

Setup Boilerplate for Mod

  • Each mod needs to be in a package
  • Each mod package needs a main class
  • Main class needs an instance, a server proxy, preinit, load and postinit.
  • Proxy classes provide shared code between server and client (we won’t use these)
  • Each new ‘thing’ lives in a new class and derives from a similar ‘thing’

A new ‘thing’ : a block

  • Block needs a look
    • Texture in mods.MODNAME.textures.blocks
  • Respond to being placed by the player
    • Set more blocks
  • Create instance of a block, and set it up some default features of that block.
  • Register block, its name and block harvest level
  • Build and test

anything can happen, including crashes, lag, glitches: i.e. BUGS!

Package the mod

  • Recompile.bat
  • Reobfuscate.bat
  • Code
    • ‘mcp\reobf\minecraft\modname’ -> mod.zip\modfolder\modname
  • Textures
    • ‘mcp\src\minecraft\mods’ -> mod.zip\modfolder\mods

Email it to your friends that have FML installed for 1.5.2

Find my mod and source code here on Dropbox.