Ninjaicon action arena game.

Lengthy title, but thats because I haven’t thought up a name for it yet ^^;
I started this new project as opposed to my previous one because there is a dead motherboard between me and the hard-drive its on >_<

Ok so this is a very simple game in wich all the characters, player and enemies alike, are emoticon-like.
The entire goal of the game is to just SURVIVE killing as many enemies as you can before you die and reach a highscore.

Download from dropbox (update 7; With much haggeling, groveling and lots of patients and support of Goran: THE SCORE BOARD!!!, nicer looking start scene):
In order for the .blend to save scores you should tick the "Run Blender as Admin"box in the program attributes. Changing the folder that its in from “read only” will only be a temporary solution; Windows likes to keep its folders read only (making me wonder why the devil it has the option to switch it off!)

STANDALONE .EXE (update 3):
There should be no problems with saving scores on this one, though should you get problems anyway run it as admin.

(old vid:

My score: 180 (<- I reset my score with the implimation of the Master enemy)

E : forward
D : forward (towards camera)
S : left
F : right
Mouse move: rotate cam
W : jump
lmb : attack
— Combos:
— lmb + lmb + lmb : strongest attack, works best on single enemies.
— lmb + lmb + rmb : widest attack, works on large groups. Causes knockback.

Not WASD because WAZ and EFC are kept for jumping and other possible controls I haven’t decided upon yet.

Guy A : Very simple enemy. Will attack with one slash.
Guy B : This one makes a three part combo that is nearly impossible to dodge when you’re too close.
Mage : Fires bolts of energy at you. Runs away when you come too close. Bolts are very hard to dodge.
Master : Done, though kinda buggy. Thows hat at you and runs away when you come close, but when you come even closer it’ll strike you with its claw and defend itself with his hat till you’re gone. WARNING; HE’S MEGA TOUGH)

Tings to do:
The Master: Debug
The actual arena : Models: 30%, Textures: 1%, Animations: 50%, Sounds 0%, Spawn: 0%, Logic: 5%

Sticky keys and skipped animations with more than 5 enemies on-field.
Lifebar fills up when character takes saké only when hit by an enemy.
There is no way of viewing the scoreboard without having played the game.

Really nice and fun to play,logic bricks looks very nice and neat also the models are really nice.
As for recording gameplay I might be able to record a small video but I’m not sure so I can’t promise you anything,also I suggest you to try reduce the polygons on the level also on the character also try to use Open Broadcast Software recorder since its really and amazing screen recorder.

Thanks ^^
Yeah I know, the poly count; will fix that soon XD
Open Broadcast software… ok will look into that, thanks again!

(Anybody else actually try the game???)

I played it when you first posted it. I had some difficulty getting the attacks to actually hit the enemies but I remember figuring it out at some point. Do you have any improvements?

Its in the first post, I edit the post with the new updates described every time.
No new improvements with the combos, but there,s a HUD now that shows life and score, a play game screen and a game over screen.
Oh, and all the characters have been down-ressed ((lower poly count).

I still recommend you play it in the standalone player though…

May I suggest to add some sort of ‘auto-targetting’ so that the first enemy that get hits becomes the target object and the player always tracks to it until the player kills him or moves away from him… that would make attacking much easier… just a suggestion :slight_smile:

Yeah, good idea, though I’m not sure how to do that yet.
I’ll definatly look into it though ^^

The game doesn’t start here, due to a resource path error. Terminal log:

Error: Unable to pack file, source path '/Desktop/ftblender/chinyen.ttf' not found
Error: Unable to pack file, source path '/Desktop/ftblender/chinyen.ttf' not found
Font file doesn't exist: //../../../Desktop/ftblender/chinyen.ttf
Can't find font: /Desktop/ftblender/chinyen.ttf
Can't find font: /Desktop/ftblender/chinyen.ttf

A workaround is to replace the “missing” chinyen.ttf with the default bfont.
The game works well even in embbeded mode (just switch to “3D View full” Screen layout for best results)
I didn’t notice any abnormal performace slowdown due to increasing number of enemies in game.

The game is fun and the ninja spheres look great.

Tested on Ubuntu 13.04, AMD HD5450, Catalyst 13.4, Blender 2.68a

Oh come on, blender doesn’t pack fonts!? o_o
And thats such a fun font too :C

No slowdowns? Fast computer! I have an AMD Dual-Core Processor E1-1200 with AMD Radeo HD 7310 intregated graphics card, and with +6 enemies it starts lagging.
Glad you like it ^^

Master has been added.
There is now a standalone .exe.
Read first post for details.

Updates are pretty good. The player needs some way to tell that they have hit an enemy. Some ideas would be to put a health bar over their head so you can see that go down, flash the enemy when hit, or add a short-lived ‘slash’ effect on them when hit.

I don’t think that the mages’ attacks should be able to track the player unless the player has a way to block the attacks. As it is the mages can hide behind a wall and lob homing attacks against you and there is nothing you can do about it.

My intention is to have small red bits look like they’re flying off the enemy when hit (green bits coming off the master hats)
(Same for the ninja, only black and yellow, oh, and a white flash when hit by a bolt)

I agree, the mages tracking can be lightened, my intention was that the bolts bend somewhat towards the player, but not follow you around everywhere.

BTW, any way of solving the font and sound problem in the standalone???

Also, the bolts go through buildings, quickly killing you!
There should be a way to see if the one of the avatars has been hit! Since the enemies have no health bar, there shuold be some indicator that the hits landed! Controls are very hard as well, it’s more like 90º turn everytime. Can you add a move turn and mouse button strike. LMB Attack, RMB block.

I’m going to add boxes (invisible) around wall, I’ll give those the property of “wall” and make them destroy energy bolts.
I’m also hoping that that’ll solve the problem with running characters through the wall.
Also, like I said in the previous post, I’m going to make red bits fly off the enemies when they’re hit, and black bits off the ninja.
Controls are going to change definitly and most likely to the mouse, ust tell me, would it be better to have 3rd person mouselook?

Btw, is there any way to make enemies flee better? Instead of just mindlessly running up against walls?

If in understand the flee problem correctly, you may choose a destination for the enemy that satisfies some predefined condition. Like “i want to find a spot where the player can’t see me”:

pivot = enemy.worldPosition
for point in ImaginaryXYGridCenteredAt(pivot):
    if player.rayCastTo(point) != enemy:
        point might be a suitable location for the steering actuator

Because enemies are not points you make the visibility test against the eight points that represents the approximated bounding volume of the enemy and you need a fallback strategy because the approach doesn’t guarantee a solution but it’s very easy to implement.

So I just copy’n’paste that?
Sorry, only just got some of the ultimate basics from py ^^;

Well, I made a test and it turns out that the required script is a bit longer than the pseudo code i posted yet it looks to work, while keeping a relative simplicity.

First, a video:

The enemy has a “flee” boolean property. A sensor is bound to that property, when it is true the enemy is supposed to seek cover. The sensor is set to update itslef every 100 logic ticks but the threshold could be lowered or raised. The sensor is linked to a python-module controller and the controller to a Steering actuator.
The script uses the navigation mesh to test if a point in the virtual grid is reachable but (in theory) a point-in-bound test could be used to avoid that but I don’t know how to test if a point intersects the boundaries of an object in the scene with the python apis (something like scene.pickObjects(point) would be great to have).
With that setup, the script is as follows:

import bge

def isReachableLocation(nav, start, point):
    #using a navigation mesh tests if a point is reachable
    #here we assume that a position is reachable if the path built by the
    #navmesh ends "more or less" at that point
    path = nav.findPath(start, point)
    last = path[len(path) - 1]
    samex = int(last[0]) == int(point[0])
    samey = int(last[1]) == int(point[1])
    return samex and samey

def generateXYGrid(steering, center, cellSize, cellCount):
    #generate a virtual grid around a given location
    hsize = (cellSize * cellCount) / 2
    minx = center[0] - hsize
    miny = center[1] - hsize
    cells = []
    for x in range(0, cellCount):
        for y in range(0, cellCount):
            cellx = minx + (x * cellSize)
            celly = miny + (y * cellSize)
            cellz = center.z
            pos = (cellx, celly, cellz)
            if isReachableLocation(steering.navmesh, center, pos): 
    return cells

def positionIsHiddenFromPlayer(pos, enemy, player):
    #test if the player can see the given location
    hit = player.rayCastTo(pos)
    return hit and (hit != enemy)

def getClosestPositionHiddenFromPlayer(grid, enemy, player):
    #tries to find a cell in the virtual grid that the player can't see
    #(because of some obstacle). Picks the nearest suitable cell, if any.
    minDistance = None
    result = None
    for cell in grid:
        hidden = positionIsHiddenFromPlayer(cell, enemy, player)
        if hidden:
            distance = enemy.getDistanceTo(cell)
            if (minDistance == None) or (distance &lt; minDistance):
                minDistance = distance
                result = cell
    return result

def flee(controller):
    #python module controller's function
    #requires a Steering actuator, set to "path finding", with a
    #navigation mesh and a destination target that can be moved
    PLAYER_OBJECT_NAME = "player"
    scene = bge.logic.getCurrentScene()
    player = scene.objects[PLAYER_OBJECT_NAME]
    enemy = controller.owner
    steering = controller.actuators[STEERING_ACTUATOR_NAME]
    playerPosition = player.worldPosition
    grid = generateXYGrid(steering, player.worldPosition, 5, 10)
    position = getClosestPositionHiddenFromPlayer(grid, enemy, player)
    if (position != None):
        #position is a suitable cover = position
        print("fallback strategy goes here")

It is far simpler than how it looks. It is like saying “ok, the enemy is at point p, if i move X units left, can the player see me or is there anything that blocks his vision?” If the answer is yes, the enemy moves there (it actually moves the target of his steering actuator and the actuator moves the object). If the answer is no, it tries another position. The set of positions that are tested are the cells of the imaginary grid.

In the script I used the simpler “player can see a single point” test instead of approximating the volume of the enemy to a cubic bounding volume because the spacing between cells provides some degree of approximation by itself.
And I was too lazy to write that part too :D.

Of course i made no extensive test but it seems to work and i think that the theory is sound.

Below the test file (black sphere is the player, controlled by arrows, the red sphere tries to seek cover from it)

Wow! O_o
With a bit of tweaking I got to work this almost perfectly (there’s still that it sometimes thinks ramming the character is the best way to find a safespot, But thats not too bad)
The changes I’ve made are:
I upped the amount of pulses from one per 100 to one per 10.
I increased the speed too, this helped with the more frequent pulses and avoideds the ninja from catching up too quickly.

How am I intending to implement it:
Well I noticed that when it picked a flee path it’ll continue till it reached it, no matter how far away the destinatio is.
So; The fleeing will be on a differant state with a near sensor that is there to sense… well it would be better to call it a far sensor.
Anyway, after a certain distance, namely its normal range that it attacks at it’ll return to its rest state… or maybe attack state…

I was thinking about this and I spotted an unrelated error in the code I’ve posted. In the “flee(controller)” function, I wrote:

grid = generateXYGrid(steering, player.worldPosition, 5, 10)

but it was meant to be:

grid = generateXYGrid(steering, enemy.worldPosition, 5, 10)

Otherwise it checks the locations that are “around” the player but it’s the enemy the pivot point of the grid.
Going back to the “enemy fleeing toward the player” issue, I can’t think of a fix because the problem boils down to the answer to the question: what do I do if my enemy is between me and the only safe spot? Then it is no more a problem of safe locations but of how do I reach that location in the best possible way.
Notice however that if what you need is just a way to make the enemy stay away from the player - without seeking cover - then the code is easier: while building the grid you simply discard the half that extends toward the player, pick some point that is reachable and move the enemy there.