It's definitely helping me... Somehow or another, I'm a few days away from having a release-quality game. All because I've been fooling around with 500 a lot.
In response to Ter13
Ter13 wrote:
That looks awesome! Another neat effect might be sequentially having the blocks above collapse, and do a jello-like effect when they hit the block below them by scaling axes but preserving total area.

I gave this a go, having the blocks in each column drop sequentially as opposed to all together, and with a quick little squishy effect as they land. I will eventually get around to rewriting this and turning into some sort of game, but for now it's fun to tinker with.
That looks brilliant!
In response to Danny Roe
Danny Roe wrote:
I gave this a go, having the blocks in each column drop sequentially as opposed to all together, and with a quick little squishy effect as they land. I will eventually get around to rewriting this and turning into some sort of game, but for now it's fun to tinker with.

Holy crap, that looks great! I'd say it's "game" enough as-is, at least for someone who wants a neat little time-waster. (I'd guess that the majority of the "game" trappings that could be added on probably lie in a scoring system and the test for round-end/no moves condition)
In response to Fugsnarf
Fugsnarf wrote:
I think the electrons should move faster overall.

And I think you're right!



(I snuck a few extras in there while I was at it; triggered by verbs. I might just cram all kinds of settings and options into this thing with some slider or toggle interface elements and put it out as a "game")

C'mon! Anyone got any more stuff to show off? Or is everyone keeping their cards close for the contest? :)
Nothing I can really show off very well at the moment. I have made a slight improvement to sidescroller graphics, rather than having 4-directional icons with 2 unused, I'm just setting up a couple of matrixes to handle directional facing from a single-directional icon:

var
matrix/eastface = matrix(1,0,0,0,1,0)
matrix/westface = matrix(-1,0,0,0,1,0)

//this is the standard game controller
controller
playermove
var
mob/player/mob
control_dir = 0 //used to determine what direction we're trying to move
proc
//called during repeating inputs.
//this is only triggered when one or more inputs are active
//stops when no inputs are live anymore
input_repeat()
while(active_inputs)
if(control_dir)
if(mob.canmove)
//by default, move us left or right
step(mob,control_dir,mob.step_size)
sleep(world.tick_lag)
//set up the macros
initialize()
..()
src.mob = src.client.mob
registerMacro("game","jump","W")
registerMacro("game","left","A")
registerMacro("game","down","S")
registerMacro("game","right","D")

//called internally whenever a macro is pressed.
handle_input(var/axis,var/value,var/time)
var/inactive = 0
if(active_inputs==0)
inactive = 1

//check for the name of the axis (button)
switch(axis)
if("left")
if(value)
//make sure that the mob's graphic is facing the right direction, and
//only try to move one direction at a time.
control_dir |= WEST
control_dir &= ~EAST
mob.transform = westface
else
control_dir &= ~WEST
//if the opposite direction is pressed, revert to moving east
if(inputs["right"])
control_dir |= EAST
mob.transform = eastface
if("right")
if(value)
control_dir |= EAST
control_dir &= ~WEST
mob.transform = eastface
else
control_dir &= ~EAST
if(inputs["left"])
control_dir |= WEST
mob.transform = westface
if("jump")
if(value)
//inform the engine that this is not a repeating input by decrementing active_inputs
active_inputs--
//only jump if grounded
if(mob.grounded&&mob.canmove)
//reset the jump matrix
mob.jump_ang = matrix(1,0,0,0,1,0)
mob.holdjump = 1
spawn(-1) //spawn so we don't hang up this keypress
mob.jump() //tell the mob to jump
else
active_inputs++
mob.holdjump = 0
..(axis,value,time) //call default behavior
//if we currently have an active input
//and we didn't have one at the start of this proc,
//tell the input_repeat method to run.
if(inactive&&active_inputs)
input_repeat()


This setup, by the way, utilized my InputHandler library, as well as my DatumPoint library and a matrixstep function I wrote:

var
//workingpoint is a global point type
//use this for disposable points rather than making new ones all the time
//don't rely on the values after a sleep or spawn!
point/workingpoint = new/point()
proc
//this function uses DatumPoint as a library.
//it's sort of like step, but uses a matrix for transforms
matrixstep(var/atom/movable/O,var/forcedir=null,var/matrix/m,var/step)
//set up the workingpoint to the current loc of the object we're moving
workingpoint.Set(O)
//apply the matrix to the step size
workingpoint.Add(m.b*step+m.c,m.e*step+m.f)
var/atom/nl = workingpoint.getLoc()
//make sure the step is in world boundaries
if(nl)
//if we are forcing a direction to face, apply that, otherwise, keep current facing
var/d = forcedir
if(d==null||d==0)
d = get_dir(O,nl)
//do the move
. = O.Move(nl,d,workingpoint.getPixelX(),workingpoint.getPixelY())
if(.)
//make sure to apply movement remainders
O.remainder_x = workingpoint.getRemainderX()
O.remainder_y = workingpoint.getRemainderY()
else
//ensure we didn't partially move, then hit a map edge
//this is probably bugged.
var/mx = workingpoint.x+O.bound_width
var/my = workingpoint.y+O.bound_height
if(workingpoint.x<1||workingpoint.y<1||round(mx)>=world.maxx*TILE_HEIGHT||round(my)>=world.maxy*TILE_WIDTH)
O.Bump(null)
return .
else
O.Bump(null)
return 0
In response to SuperSaiyanGokuX
SuperSaiyanGokuX wrote:
Holy crap, that looks great! I'd say it's "game" enough as-is, at least for someone who wants a neat little time-waster.

I still need to come up with a better way to track empty columns and slide the remaining columns to the left (I'll probably start a topic to get some input) and locate the source of a couple of random crashes. There are also a load of other features I want to include after I get the basics done, such as ledges, bombs, reinforced blocks, different modes of gameplay etc..
In response to Ter13
I really dig the side-scroller method you got goin there. For some reason it annoys me that you can't pick two or three directions if you want to.
In response to Ter13
I'd recently (some time this summer) tried out Unity and I really like how they handle input. I've been using my own input system inspired by Unity's Input.GetAxis() in all of my latest test projects.
client
ControlsSetup()
controls.Set("Move", "d", "a")
controls.Set("Jump", "space")
controls.Set("Primary", "mouse left")

mob
Login()
..()
TickStart()

Tick()
var jumping = controls.Get("Jump")
// jumping can be 0 or 1

var shooting = controls.Get("Primary")
// 0 or 1

var moving = controls.Get("Move")
// Moving can be
// 0: not moving
// 1: moving right
// -1: moving left
// So it'd be used like:
vel_x = lerp(vel_x, moving * move_speed, 0.8)
// or whatever your method of acceleration is.

// etc.

// Jumping could also just use an event
ButtonDown(Button)
switch(Button)
if("Jump")
...

This isn't related to v500, but I just was curious if other people would benefit from this kind of style.
Just as a complete aside, here's some undocumented goodness if you don't want to use multiple lines to setup a datum:

matrix(angle, MATRIX_ROTATE)   // although this is equivalent to turn(matrix(), angle)
matrix(x, y, MATRIX_SCALE)
matrix(x, y, MATRIX_TRANSLATE)

Those don't work at compile-time for initializing a var (they could, I just didn't want to try working the same logic into the compiler part), but they'll work dandy in a proc. The result is a /matrix and can be used with operators.

I didn't document this for the reason that it's more or less too complex to bother with in the reference. The matrix() proc is rather a workhorse, but all most people really need out of it "above the hood" is the ability to make a new matrix or copy one. But I'll leave it as an exercise for the curious how they can copy a matrix's values into a 6-item list.
In response to Lummox JR
I think there's a memory leak in those 3 functions.
mob
verb/Leak()
var start_time = world.timeofday
for(var/n in 1 to 1e5)
matrix(0, MATRIX_ROTATE)
// works the same for SCALE and TRANSLATE
src << world.timeofday - start_time

The output, after using the verb a few times:
4
7
9
13
15


When the matrix(...) line is replaced with just matrix(), the output is consistently:
2
2
3
3
2


edit: Interestingly, the leak is causing subsequent matrix() (no arguments) calls to take longer.
A very rough little experiment, not sure how clear the bullets are. Something along the lines of changing the range in a Tower Defence game.
In response to Kaiochao
Fantastic catch! Please post that as a bug report and I'll get that resolved.
In response to Kaiochao
Kaiochao wrote:
I'd recently (some time this summer) tried out Unity and I really like how they handle input. I've been using my own input system inspired by Unity's Input.GetAxis() in all of my latest test projects.

I don't like your approach quite as much, actually Largely, it's the Tick() function. You should check out InputHandler's source code. It is pretty clean and doesn't depend on infinite loops. More or less, it detects input cleanly using registered axes similar to yours, but handle_input() is only called on a keypress or a keyrelease of a registered axis. It lets you make repeating processes via code similar to how I handled it in input_repeat().

It also has an option for a buffer size, which lets you keep track of things like combos and double-taps.

Unity's approach always felt a little... 1980s to me.
In response to Ter13
The Tick() function runs off of one global infinite loop. I like using a main game loop for my physics stuff.

For example, when you release all your keys, you shouldn't instantly stop moving just because your character is not receiving any input, because it's a physical object; that's what the vel_x line implies. The lerp() allows it to gradually accelerate and decelerate based on player input.

edit: Unity has options of easing (with the same curves that animate() now uses) player input, which means the value you get for GetAxis() (as opposed to GetAxisRaw()) changes according to the duration the key is held. I'd like to add that, but I... haven't needed it yet.

edit: The point of my system is that having neither D nor A down is the same as having both D and A down, according to the controls manager. Instead of, say, checking each key and setting up a BYOND direction to determine which direction to go (or even worse; stepping right and then left in the same frame), we just get 0 as the "Move" input, which automatically translates to no acceleration along the x-axis.
If you look at a lot of games like Super Meat Boy, responsiveness of controls is a big thing for the game.

One of the things I did for physics, was essentially only running physics code as far as it needed to be run.

With gravity-enabled objects, I'm using a special type of movable called a collider. Basically, it has a bounding box that matches the width of the bounding box of the attached object.

The collider detects dense objects one pixel beneath the mob while it's considered grounded, which allows it to count the number of supporting tiles.

//override move to provide a Moved() function
//this is called whenever a move is successful
atom/movable
Move(var/atom/NewLoc,var/Dir=0,var/step_x=0,var/step_y=0)
var/oldloc = src.loc
var/odir = src.dir
var/osx = src.step_x
var/osy = src.step_y
. = ..(NewLoc,Dir,step_x,step_y)
if(.)
Moved(oldloc,odir,osx,osy)
proc
Moved(var/atom/OldLoc,var/Dir=0,var/step_x=0,var/step_y=0)
return

//colliders check that a mob is standing on a platform
collider
icon = 'test.dmi'
parent_type = /atom/movable
density = 0
layer = MOB_LAYER
var
support = 0

mob
step_size = 3
var
tmp
grounded = 1 //keep track of if we are on the ground
collider/grounding = new() //grounding is a collider that checks that we have platforms under us
gravity = -16 //how much gravity is applied to the mob when falling
fallstart
proc
fall()
//animate the fall
//this is a .3 sec one-time animation
var/fs = world.time
fallstart = fs
src.grounded = 0
src.icon_state = "fall-in"
spawn(3)
//delay and make sure we are still falling
//start the repeating fall animation
if(!src.grounded&&src.fallstart==fs)
src.icon_state = "fall"
//get ready to fall until we hit something
var/step = 1
var/velocity = 0
while(step)
//don't fall faster than gravity, but increase velocity by 1/60th of gravity.
//falling acceleration reaches terminal velocity after 1 second.
velocity = max(gravity*2,velocity+gravity/60)
//perform a matrix step and get the result to determine if still falling
step = matrixstep(src,null,eastface,velocity)
sleep(world.tick_lag)
//animate a 2 second one time animation for landing
src.icon_state = "land"
src.grounded = 1
src.Moved(null)
//halve the step size while landing
sleep(2)
src.icon_state = ""
return
Moved(var/atom/OldLoc,var/Dir=0,var/step_x=0,var/step_y=0)
//make sure we are on the ground
if(grounded)
if(src.loc)
//set up the working point
workingpoint.Set(src)
workingpoint.y -= 1
//it should be 1 pixel below src
var/turf/t = workingpoint.getLoc()
//get the location
if(t)
//move the grounding collider and check the number of supporting platforms
var/px = workingpoint.getPixelX()
var/py = workingpoint.getPixelY()
grounding.Move(t,0,px,py)
if(grounding.support==0)
//if no supports, start falling
src.fall()
return
if(grounding.loc)
grounding.loc = null
grounding.support = 0
Stat()
stat("supports",grounding.support)
New()
. = ..()
//set up the grounding's bounding box to the width of this mob and 1px tall
src.grounding.bound_x = src.bound_x
src.grounding.bound_width = src.bound_width
src.grounding.bound_height = 1
src.grounding.transform = matrix(src.bound_width,0,src.bound_x+round(src.bound_width/2),0,1,0)


Now, platforms allow players to jump up through them, but not pass through from the top.

They also count how many supporting platforms are beneath the object, by incrementing and decrementing the support variable of any colliders crossing this platform.

obj
step_size = 2
platform
icon = 'platform.dmi'
density = 1

//allow us to jump through from below
Cross(var/atom/movable/o)
if(o.y>src.y&&o.density)
return 0
return 1

//when colliders cross a platform, support them
Crossed(var/atom/movable/o)
if(istype(o,/collider))
var/collider/c = o
c.support++

//when collider uncross a platform, unsupport them
Uncrossed(var/atom/movable/o)
if(istype(o,/collider))
var/collider/c = o
c.support--

//check icon_states to ensure proper bounding size
New(var/state=null,var/loc=null)
if(!src.loc)
src.loc = loc
if(!src.icon_state)
src.icon_state = state
if(src.icon_state=="2")
src.bound_x = 16
src.bound_width = 16
else if(src.icon_state=="1")
src.bound_width = 16


Since fall() is independently operating, and all physics behavior is determined by the object itself, only moving objects have live physics loops running.
In response to Kaiochao
I'll just go ahead and post that report.
In response to Lummox JR
Lummox JR wrote:
I'll just go ahead and post that report.

Kaiochao is the laziest person ever when it comes to submitting bug reports.
At least I have the dial-up excuse. What's your excuse Kaiochao, huh, huh?!
In response to Nadrew
Usually I manage to get someone from Chatters to submit bug reports for me.
Page: 1 2 3 ... 11 12 13 14 15 ... 17 18 19